Bidirectional Automatic Sync
Overview
Readstr now features fully automatic bidirectional sync - your subscriptions, categories, and tags sync seamlessly across all your devices without any manual intervention.
How It Works
π Two-Way Sync
Upload (This Device β Nostr Relays)
- β Happens automatically after every change
- β Triggers: Add feed, remove feed, update tags, change category
- β Timing: 500ms after the change
- β Includes deleted feeds for proper sync
Download (Nostr Relays β This Device)
- β Happens automatically every 15 minutes
- β Triggers: On page load, when fetching feeds
- β Creates categories if they donβt exist
- β Only pulls if >15 minutes since last sync
π± User Experience
From the Userβs Perspective:
-
On Device A: Add a feed to βTechnologyβ category
- Feed is added immediately
- 500ms later: Automatically syncs to Nostr (silent, background)
-
On Device B: Open the app (or wait up to 15 minutes)
- Automatically detects new feed from Nostr
- Creates βTechnologyβ category if it doesnβt exist
- Adds the feed with proper category assignment
- All happens seamlessly, no prompts or buttons
-
Back on Device A: Remove a feed
- Feed disappears immediately
- 500ms later: Deletion syncs to Nostr
-
On Device B: Next refresh (within 15 minutes)
- Feed automatically removed
- Deleted feed tracked in sync to prevent re-adding
π― What Gets Synced
Automatically synced on every change:
- RSS feed URLs
- Nostr npub subscriptions
- Feed tags (multiple tags per feed)
- Feed categories (name, color, icon)
- Deleted feeds (to properly sync removals)
Preserved properties:
- Category colors
- Category icons
- Tag associations
- Subscription metadata
π Requirements
For Auto-Export (Upload):
- β Nostr browser extension installed (Alby, nos2x, etc.)
- β Signed in with Nostr
- β
Extension must be available (
window.nostr)
For Auto-Import (Download):
- β Signed in with Nostr (any method)
- β Access to Nostr relays
If requirements not met:
- Export: Silently skips (no error shown to user)
- Import: Still works via server-side fetch
Technical Details
Architecture
User Action (Add/Remove/Edit)
β
Local Mutation (tRPC)
β
UI Updates Immediately
β
500ms delay
β
autoExportToNostr()
β
Fetch ALL subscriptions (including deleted)
β
Build subscription list with categories
β
Sign with Nostr extension
β
Publish to relays (Kind 30404)
β
Done (silent success/failure)
Mutations That Trigger Auto-Export
- subscribeFeedMutation - Adding a new feed
- unsubscribeFeedMutation - Removing a feed (soft delete)
- updateTagsMutation - Changing feed tags
- updateCategoryMutation - Moving feed to different category
Auto-Import Triggers
- getFeeds query - On every feed list fetch
- Interval check - Max once per 15 minutes
- Manual sync - Settings > Sync > Import
Data Flow
Kind 30404 Event Structure:
{
"kind": 30404,
"created_at": 1738095789,
"tags": [
["d", "readstr-subscriptions"],
["client", "readstr"]
],
"content": {
"rss": ["https://example.com/feed.xml"],
"nostr": ["npub1abc..."],
"tags": {
"https://example.com/feed.xml": ["tech", "news"]
},
"categories": {
"https://example.com/feed.xml": {
"name": "Technology",
"color": "#3b82f6",
"icon": "π»"
}
},
"deleted": ["https://old-feed.com/rss"],
"lastUpdated": 1738095789
}
}
Performance & Throttling
Upload Throttling
- 500ms delay after mutation completes
- Allows UI to settle before network request
- Prevents rapid-fire uploads during bulk operations
Download Throttling
- 15-minute cooldown between auto-imports
- Prevents excessive relay queries
- Balances freshness with resource usage
Error Handling
- Silent failures on export (logged to console)
- User never sees error modals for background sync
- Manual sync option available if auto-sync fails
Resource Usage
- Export: ~1-2 KB per event
- Import: Single relay query every 15 minutes
- No polling or WebSocket connections
- Minimal battery/bandwidth impact
Migration from Manual Sync
Before (Manual Only)
β User adds feed on Device A
β Feed stays local to Device A
β User must remember to click "Export to Nostr"
β User switches to Device B
β Must click "Import from Nostr"
β Feed finally appears on Device B
After (Automatic)
β
User adds feed on Device A
β
Automatically syncs to Nostr (500ms later)
β
User switches to Device B
β
Feed appears automatically (within 15 minutes)
β
Zero manual intervention required
Debugging
Check if Auto-Export is Working
Open browser console and look for:
π Auto-exporting subscriptions to Nostr...
β
Auto-export successful: <eventId>
Check if Auto-Import is Working
Look for server logs during feed fetch:
π Sync merge - Remote RSS URLs: [...]
π Sync merge - Remote Nostr npubs: [...]
π Sync result: X to add, Y to remove, Z local-only
Common Issues
Auto-export not triggering:
- Check if
window.nostris available - Verify user is signed in
- Check console for errors
Auto-import not working:
- Wait 15 minutes since last sync
- Check relay connectivity
- Verify subscription list exists on relays
Categories not syncing:
- Ensure both devices have category support
- Check that color/icon are being set
- Verify category names match exactly
Future Enhancements
- Conflict resolution for simultaneous edits
- Sync status indicator in UI
- Configurable sync interval (user preference)
- Offline queue for failed uploads
- Selective sync (choose what to sync)
- Sync history/audit log
- Category sort order syncing
- Hierarchical categories