diff --git a/components/common/CommonPaginator.vue b/components/common/CommonPaginator.vue
index 11cd3f9b..3f24c0bf 100644
--- a/components/common/CommonPaginator.vue
+++ b/components/common/CommonPaginator.vue
@@ -15,7 +15,7 @@ const {
   paginator: Paginator<any, any[]>
   keyProp?: string
   virtualScroller?: boolean
-  stream?: WsEvents
+  stream?: Promise<WsEvents>
   eventType?: 'notification' | 'update'
   preprocess?: (items: any[]) => any[]
 }>()
diff --git a/components/notification/NotificationPaginator.vue b/components/notification/NotificationPaginator.vue
index 6c08b264..d6dd98c7 100644
--- a/components/notification/NotificationPaginator.vue
+++ b/components/notification/NotificationPaginator.vue
@@ -4,7 +4,7 @@ import type { GroupedAccountLike, NotificationSlot } from '~/types'
 
 const { paginator, stream } = defineProps<{
   paginator: Paginator<any, Notification[]>
-  stream?: WsEvents
+  stream?: Promise<WsEvents>
 }>()
 
 const groupCapacity = Number.MAX_VALUE // No limit
diff --git a/components/timeline/TimelineHome.vue b/components/timeline/TimelineHome.vue
index 10d5c26a..9581e452 100644
--- a/components/timeline/TimelineHome.vue
+++ b/components/timeline/TimelineHome.vue
@@ -1,8 +1,8 @@
 <script setup lang="ts">
 import type { Status } from 'masto'
 const paginator = useMasto().timelines.iterateHome()
-const stream = await useMasto().stream.streamUser()
-onBeforeUnmount(() => stream.disconnect())
+const stream = useMasto().stream.streamUser()
+onBeforeUnmount(() => stream?.then(s => s.disconnect()))
 
 const maxDistance = 10
 function preprocess(items: Status[]) {
diff --git a/components/timeline/TimelineMentions.vue b/components/timeline/TimelineMentions.vue
index 8e0a925b..edc57a31 100644
--- a/components/timeline/TimelineMentions.vue
+++ b/components/timeline/TimelineMentions.vue
@@ -5,7 +5,7 @@ const paginator = useMasto().notifications.iterate({ limit: 30, types: ['mention
 const { clearNotifications } = useNotifications()
 onActivated(clearNotifications)
 
-const stream = await useMasto().stream.streamUser()
+const stream = useMasto().stream.streamUser()
 </script>
 
 <template>
diff --git a/components/timeline/TimelineNotifications.vue b/components/timeline/TimelineNotifications.vue
index 53c067ec..11e6fd4a 100644
--- a/components/timeline/TimelineNotifications.vue
+++ b/components/timeline/TimelineNotifications.vue
@@ -5,7 +5,7 @@ const paginator = useMasto().notifications.iterate({ limit: 30 })
 const { clearNotifications } = useNotifications()
 onActivated(clearNotifications)
 
-const stream = await useMasto().stream.streamUser()
+const stream = useMasto().stream.streamUser()
 </script>
 
 <template>
diff --git a/components/timeline/TimelinePaginator.vue b/components/timeline/TimelinePaginator.vue
index a6be7618..8c5831f5 100644
--- a/components/timeline/TimelinePaginator.vue
+++ b/components/timeline/TimelinePaginator.vue
@@ -6,7 +6,7 @@ import type { FilterContext, Paginator, Status, WsEvents } from 'masto'
 
 const { paginator, stream } = defineProps<{
   paginator: Paginator<any, Status[]>
-  stream?: WsEvents
+  stream?: Promise<WsEvents>
   context?: FilterContext
   preprocess?: (items: any[]) => any[]
 }>()
diff --git a/components/timeline/TimelinePublic.vue b/components/timeline/TimelinePublic.vue
new file mode 100644
index 00000000..2c1e1e16
--- /dev/null
+++ b/components/timeline/TimelinePublic.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+const paginator = useMasto().timelines.iteratePublic()
+const stream = useMasto().stream.streamPublicTimeline()
+onBeforeUnmount(() => stream.then(s => s.disconnect()))
+</script>
+
+<template>
+  <div>
+    <TimelinePaginator v-bind="{ paginator, stream }" context="public" />
+  </div>
+</template>
diff --git a/components/timeline/TimelinePublicLocal.vue b/components/timeline/TimelinePublicLocal.vue
new file mode 100644
index 00000000..829c75da
--- /dev/null
+++ b/components/timeline/TimelinePublicLocal.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+const paginator = useMasto().timelines.iteratePublic({ local: true })
+const stream = useMasto().stream.streamCommunityTimeline()
+onBeforeUnmount(() => stream.then(s => s.disconnect()))
+</script>
+
+<template>
+  <div>
+    <TimelinePaginator v-bind="{ paginator, stream }" context="public" />
+  </div>
+</template>
diff --git a/composables/paginator.ts b/composables/paginator.ts
index 7daef178..72e0791e 100644
--- a/composables/paginator.ts
+++ b/composables/paginator.ts
@@ -4,7 +4,7 @@ import type { PaginatorState } from '~/types'
 
 export function usePaginator<T>(
   paginator: Paginator<any, T[]>,
-  stream?: WsEvents,
+  stream?: Promise<WsEvents>,
   eventType: 'notification' | 'update' = 'update',
   preprocess: (items: T[]) => T[] = (items: T[]) => items,
 ) {
@@ -24,32 +24,34 @@ export function usePaginator<T>(
     prevItems.value = []
   }
 
-  stream?.on(eventType, (status) => {
-    if ('uri' in status)
+  stream?.then((s) => {
+    s.on(eventType, (status) => {
+      if ('uri' in status)
+        cacheStatus(status, undefined, true)
+
+      const index = prevItems.value.findIndex((i: any) => i.id === status.id)
+      if (index >= 0)
+        prevItems.value.splice(index, 1)
+
+      prevItems.value.unshift(status as any)
+    })
+
+    // TODO: update statuses
+    s.on('status.update', (status) => {
       cacheStatus(status, undefined, true)
 
-    const index = prevItems.value.findIndex((i: any) => i.id === status.id)
-    if (index >= 0)
-      prevItems.value.splice(index, 1)
+      const index = items.value.findIndex((s: any) => s.id === status.id)
+      if (index >= 0)
+        items.value[index] = status as any
+    })
 
-    prevItems.value.unshift(status as any)
-  })
+    s.on('delete', (id) => {
+      removeCachedStatus(id)
 
-  // TODO: update statuses
-  stream?.on('status.update', (status) => {
-    cacheStatus(status, undefined, true)
-
-    const index = items.value.findIndex((s: any) => s.id === status.id)
-    if (index >= 0)
-      items.value[index] = status as any
-  })
-
-  stream?.on('delete', (id) => {
-    removeCachedStatus(id)
-
-    const index = items.value.findIndex((s: any) => s.id === id)
-    if (index >= 0)
-      items.value.splice(index, 1)
+      const index = items.value.findIndex((s: any) => s.id === id)
+      if (index >= 0)
+        items.value.splice(index, 1)
+    })
   })
 
   async function loadNext() {
@@ -95,9 +97,9 @@ export function usePaginator<T>(
       () => {
         if (
           isInScreen
-        && state.value === 'idle'
-        // No new content is loaded when the keepAlive page enters the background
-        && deactivated.value === false
+          && state.value === 'idle'
+          // No new content is loaded when the keepAlive page enters the background
+          && deactivated.value === false
         )
           loadNext()
       },
diff --git a/pages/[[server]]/public/index.vue b/pages/[[server]]/public/index.vue
index cb5acd4f..c72c18d5 100644
--- a/pages/[[server]]/public/index.vue
+++ b/pages/[[server]]/public/index.vue
@@ -1,7 +1,5 @@
 <script setup lang="ts">
-const paginator = useMasto().timelines.iteratePublic()
-const stream = await useMasto().stream.streamPublicTimeline()
-onBeforeUnmount(() => stream.disconnect())
+
 
 const { t } = useI18n()
 
@@ -19,8 +17,6 @@ useHeadFixed({
       </NuxtLink>
     </template>
 
-    <slot>
-      <TimelinePaginator v-bind="{ paginator, stream }" context="public" />
-    </slot>
+    <TimelinePublic v-if="isMastoInitialised" />
   </MainContent>
 </template>
diff --git a/pages/[[server]]/public/local.vue b/pages/[[server]]/public/local.vue
index d66fde81..303a4796 100644
--- a/pages/[[server]]/public/local.vue
+++ b/pages/[[server]]/public/local.vue
@@ -1,7 +1,4 @@
 <script setup lang="ts">
-const paginator = useMasto().timelines.iteratePublic({ local: true })
-const stream = await useMasto().stream.streamCommunityTimeline()
-onBeforeUnmount(() => stream.disconnect())
 
 const { t } = useI18n()
 
@@ -19,8 +16,6 @@ useHeadFixed({
       </NuxtLink>
     </template>
 
-    <slot>
-      <TimelinePaginator v-bind="{ paginator, stream }" context="public" />
-    </slot>
+    <TimelinePublicLocal v-if="isMastoInitialised" />
   </MainContent>
 </template>
diff --git a/pages/[[server]]/tags/[tag].vue b/pages/[[server]]/tags/[tag].vue
index 005d904b..717ac746 100644
--- a/pages/[[server]]/tags/[tag].vue
+++ b/pages/[[server]]/tags/[tag].vue
@@ -6,8 +6,8 @@ const masto = useMasto()
 const { data: tag, refresh } = $(await useAsyncData(() => masto.tags.fetch(tagName), { watch: [isMastoInitialised], immediate: isMastoInitialised.value }))
 
 const paginator = masto.timelines.iterateHashtag(tagName)
-const stream = await masto.stream.streamTagTimeline(tagName)
-onBeforeUnmount(() => stream.disconnect())
+const stream = masto.stream.streamTagTimeline(tagName)
+onBeforeUnmount(() => stream.then(s => s.disconnect()))
 
 if (tag) {
   useHeadFixed({