Hyperlocal communities through physical QR codes and GPS verification.
Scan a QR code at a location β Prove you're there with GPS β Join the community.
Peek creates communities for people who've shared the same physical space. Scan a QR code at a cafΓ©, park, or event, prove you're actually there with GPS, and join a hyperlocal group. The first person to scan becomes the admin. Members keep access forever, but new members must physically visit the location to join.
Built on Nostr (NIP-29), Peek bridges physical spaces with decentralized digital communities.
- Scan QR code at a physical location (cafΓ©, park, building, event)
- Prove presence via GPS verification (within 25m, accuracy β€20m)
- Join community - chat and connect with others who've been there
Phase 1: First Scan (Community Creation)
- Fresh QR code β First scanner creates the community
- Scanner's GPS location becomes the permanent community location
- First scanner automatically becomes founding admin
Phase 2: Subsequent Scans (Join Flow)
- Existing community β Show preview (name, member count)
- GPS validation required: within 25m of established location
- Automatic membership on successful validation
- Validation: Must be within 25 meters of community location
- Accuracy: GPS accuracy must be β€20 meters
- No Photos: GPS-only verification (simpler, privacy-focused)
- One-Time: Prove presence once, keep access forever
Peek uses a frictionless identity progression:
Start Anonymous:
- Automatic ephemeral identity on first use
- No signup required - join communities immediately
- Zero friction for new users
Upgrade to Permanent:
- Link to your existing Nostr account
- Or create a new Nostr identity
- Migration preserves all memberships and admin status
- Uses kind:1776 events for verifiable identity continuity
Technical Details: See NIP-XX Identity Migration Draft
This allows users to try Peek instantly (anonymous) then commit to a permanent identity when ready, without losing access to communities they've joined.
- Communities are NIP-29 groups on
wss://communities2.nos.social - All membership stored on relay (no central database)
- Direct group addition via kind:9000 events
- No invite codes or tokens - pure Nostr protocol
- Censorship-resistant, decentralized
Admins can:
- Edit community: Name, description, picture
- Manage members: Remove members from group
- Manage roles: Promote/demote admin status
- View members: See who's joined the community
- No GPS tracking: Coordinates validated once, never stored
- Geohash for discovery: Public map shows ~1km precision only
- No central database: All data in NIP-29 relay events
- Decentralized identity: Nostr-based, user-controlled
- Physical-first discovery: No global search, must scan QR
- Frontend: React PWA (Vite, TypeScript, Tailwind CSS)
- Backend: Rust validation service (Axum web framework)
- Protocol: Nostr (NIP-29 groups, kind:1776 identity migration)
- Relay: wss://communities2.nos.social (groups_relay)
- Libraries: nostr-tools, nostr-sdk, geo crate, leaflet
- Node.js 20+
- pnpm 8.15+
- Rust 1.75+
- Docker and Docker Compose (optional)
git clone https://github.com/verse-pbc/peek.git
cd peekpnpm installcp .env.example .env
cp packages/validation-service/.env.example packages/validation-service/.env
cp packages/pwa-client/.env.example packages/pwa-client/.envIMPORTANT: Edit the .env files and add your Nostr keys:
- Generate keys:
nak key generate - Add relay admin key to
RELAY_SECRET_KEY - Add service keys for
SERVICE_NSEC/SERVICE_NPUB - Never commit
.envfiles - they are gitignored for security
Note: Uses
wss://communities2.nos.socialby default. No local relay required!
pnpm devpnpm dev:pwa # PWA client on http://localhost:3000
pnpm dev:validation # Validation service on http://localhost:3001docker-compose up --buildpnpm dev- Run all services in development modepnpm build- Build all packagespnpm test- Run all testspnpm lint- Run lintingpnpm typecheck- Run TypeScript type checkingpnpm docker:up- Start validation service in Dockerpnpm docker:down- Stop Docker servicespnpm docker:logs- View validation service logspnpm clean- Clean all build artifacts
peek/
βββ packages/
β βββ pwa-client/ # React PWA
β β βββ src/
β β β βββ components/ # UI components
β β β βββ pages/ # Routes (/, /c/{uuid})
β β β βββ services/ # Relay, group, identity services
β β β βββ lib/ # QR scanner, location capture
β β βββ tests/
β βββ validation-service/ # Rust backend
β βββ src/
β β βββ handlers/ # HTTP + Nostr gift wrap handlers
β β βββ services/ # Relay client, identity migration
β β βββ lib/ # Geohash, location validation
β βββ tests/
βββ specs/ # Feature specifications (for reference)
1. User scans QR β opens /c/{uuid}
2. If not member β JoinFlow component
3. GPS capture β Send to validation service (NIP-59 gift wrap)
4. Validation service checks: distance β€25m, accuracy β€20m
5. If valid β Service adds user to NIP-29 group (kind:9000)
6. User gets membership, sees community feed
1. User joins with anonymous ephemeral key (auto-generated)
2. User later links to permanent Nostr identity
3. Migration event (kind:1776) published with dual signatures
4. All memberships transfer to new identity
5. Old identity resolves to new identity via migration chain
See NIP-XX Identity Migration for protocol details.
All state lives in NIP-29 relay events:
- kind:39000 - Community metadata (name, about, picture)
- kind:39001 - Admin list
- kind:39002 - Member list
- kind:9 - Chat messages
- kind:1776 - Identity migrations
No Redis, no PostgreSQL - pure Nostr protocol.
Start completely anonymous, no signup. Upgrade to permanent identity when ready without losing anything.
Everyone in the community has physically visited the same place. Higher trust than purely digital groups.
Built on Nostr - no platform lock-in, censorship-resistant, user-owned identities.
- GPS validated once, never tracked
- Public discovery map shows ~1km precision (geohash)
- No photo storage or history
MIT