A provably human anonymous message board. Every voice is verified.
Arkora is a World App miniapp where users post, vote, and converse anonymously - but every account is backed by a unique World ID proof of humanity. No bots, no fake accounts, no duplicate identities.
World ID Orb proofs are validated directly on World Chain via the WorldIDRouter smart contract - not on Worldcoin's centralized servers. Proof validation is settled by blockchain consensus.
Live: arkora.app | Twitter: @humansposting | License: MIT
- Infinite-scroll feed with board filtering
- Three feed modes: Curated (hot-ranked), Following, Local (GPS radius)
- 40+ topic boards with fuzzy search and dynamic creation
- Post quotes, reposts, and threaded replies
- Post impressions (view count, deduplicated per verified human)
- Multi-entity search across boards, people, and posts with prefix-first matching
- Bookmarks and native share sheet
- Sybil-resistant polls - one verified human, one vote, cryptographically enforced
- Timed (24h / 3d / 7d) or perpetual duration
- Live vote percentages with inline results
- Three identity modes: Anonymous (fresh tag each post), Alias (persistent derived handle), Named (World ID username)
- Per-action identity: choose anon/alias/named on each post or reply independently
- Social gating: follow, DM, tip, and subscribe require named mode
- Confessions board - force-anonymous, completely unlinkable
- Human Karma and reputation tiers displayed on profiles and feed cards
- Live ephemeral Rooms with Clubhouse-style participant grid and speaking indicators
- End-to-end encrypted DMs (ECDH Curve25519 + AES-256-GCM)
- In-app and native push notifications (replies, mentions, follows, DMs, tips, quotes)
- @ mention autocomplete in composers
- WLD tips with push notification to recipient
- Creator subscriptions
- Skin shop (accent color customization, 1 WLD each, with live preview before purchase)
- Font shop (7 Google Fonts, 1 WLD each, with live preview before purchase)
- Block, report, and auto-hide at 5 reports
- Community Notes fact-checking system
- Comprehensive CSP headers, constant-time nonce comparison, private Pusher channels
- Input sanitization on all user-generated content
- GDPR-compliant account deletion
- Light and dark theme
- Responsive layout - adapts from mobile (full width) to desktop (centered column with side borders)
- 10 languages: English, Spanish, Portuguese, French, German, Japanese, Korean, Thai, Indonesian, Turkish (auto-detected, manually overridable)
- Server-synced preferences (theme, notifications, location persist across devices)
- Profile picture upload
- REST API for verified-human posts, polls, boards, and stats
- v1: API key authentication with CORS support
- v2: AgentKit proof-of-human auth for AI agents + API key fallback
- Premium analytics: sentiment, trends, geographic demographics (AgentKit-only)
- x402 micropayments for premium data (USDC on World Chain)
- MCP server for native AI agent tooling (Claude, GPT, etc.)
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router, Turbopack) |
| Language | TypeScript 5.6 (strict mode) |
| Database | Neon Postgres + Drizzle ORM |
| Auth | SIWE (Sign-In with Ethereum) + World MiniKit + IDKit v4 |
| Real-time | Pusher Channels (private, server-authorized) |
| File storage | Hippius S3 - decentralized storage on Bittensor subnet 14 |
| State | Zustand (with localStorage persistence) |
| Animations | Framer Motion |
| Blockchain | World Chain (chain 480) - proof verified onchain via WorldIDRouter |
| Identity | World ID 4.0 (MiniKit + IDKit, Orb verified) |
| Monitoring | Sentry (error tracking + session replay) + Vercel Analytics |
- Node.js 22 (see
.nvmrc) - pnpm (
npm i -g pnpm) - Worldcoin Developer Portal app
- Neon Postgres database
- Pusher Channels app
- Hippius S3 bucket (or any S3-compatible storage)
pnpm install
cp .env.example .env.local # fill in your credentials
pnpm db:push # push schema to database
pnpm dev # start dev server at http://localhost:3000See .env.example for all required environment variables.
World App testing: To test the full World ID flow you need World App on your phone. Use ngrok or a Vercel preview deployment to expose a public URL, then update your Developer Portal redirect URL to match.
World App opens miniapp
-> WalletConnect auto-triggers walletAuth (MiniKit.commands.walletAuth)
-> User signs SIWE message in World App
-> POST /api/auth/wallet -> verifies signature, issues httpOnly cookies:
arkora-nh (nullifierHash - unique World ID identifier)
wallet-address (EVM address)
-> Zustand store hydrates: isVerified=true, nullifierHash, user
World ID Orb verification is a separate step. The proof is validated onchain via the WorldIDRouter contract on World Chain (chain 480) - no centralized API. The verification block number is stored and displayed in-app with a link to worldscan.org.
| Mode | Description |
|---|---|
| Anonymous | Fresh Human #XXXX tag each post (default, most anonymous, unlinkable) |
| Alias | SHA256-derived persistent handle, linkable across posts but not to real identity |
| Named | World ID username shown publicly, required for social features (follow, DM, tip) |
| Mode | Description |
|---|---|
| Curated | Global feed, hot-ranked posts (Wilson-score time-decay, server-cached) |
| Following | Posts from followed users (requires auth) |
| Local | Posts near the viewer's GPS coordinates, filtered by radius |
End-to-end encrypted. Key exchange uses ECDH (Curve25519); messages encrypted with AES-256-GCM. Public keys stored server-side. Private keys live only in the client (Zustand / localStorage) - the server never sees them. Block checks enforced server-side. All DM Pusher channels are private (server-authorized).
Arkora has undergone comprehensive security auditing across all layers. Key properties:
- No SQL injection - all queries use Drizzle ORM parameterized builders, no raw SQL string interpolation
- Auth isolation - identity comes exclusively from the
arkora-nhhttpOnly cookie viagetCallerNullifier(), request body is never trusted for identity - CSRF mitigated -
SameSite=Stricton all auth cookies - World ID replay protection - enforced by the WorldIDRouter contract on World Chain, the EVM reverts on duplicate nullifier submissions
- Input sanitization - all user text passes through
sanitizeLine()/sanitizeText()(NFKC normalization + HTML stripping) before DB writes - Private Pusher channels - all per-user channels require server-side authorization
- CSP hardened -
unsafe-evalremoved fromscript-src, HSTS 2-year preload, COOP headers set - Constant-time nonce comparison - SIWE nonce validation uses
crypto.timingSafeEqual() - Rate limiting - per-endpoint, per-user sliding window on all routes
- Atomic votes - single CTE statements to prevent race conditions
- Session recovery -
authFetch()wrapper on all client API calls detects expired sessions and forces re-authentication
For vulnerability reporting, see SECURITY.md.
Arkora is being progressively decentralized across every layer:
| Layer | Status | Approach |
|---|---|---|
| Identity | Live | World ID Orb proofs validated onchain via WorldIDRouter on World Chain |
| File storage | Live (beta) | User-uploaded media stored on Hippius (Bittensor subnet 14, S3-compatible API). Production transition will move to Hippius mainnet with replication guarantees. |
| Compute | Planned | Migrate backend to Chutes (Bittensor subnet 64) with TEE-attested execution |
| Database | Planned | Evaluate decentralized or verifiable data storage options |
The goal: a social platform where proof of humanity, content storage, and application logic are all decentralized - no single operator can censor, surveil, or shut down the network.
When Arkora transitions out of beta, backend compute will move from centralized Vercel serverless functions to Chutes on Bittensor subnet 64. Chutes provides decentralized GPU/CPU compute with Trusted Execution Environment (TEE) attestation, meaning application logic runs inside hardware-isolated enclaves (Intel TDX / AMD SEV-SNP) where neither the node operator nor the host OS can inspect or tamper with the running process.
Integration plan:
- TEE attestation - Each Chutes compute node generates a cryptographic attestation report signed by the CPU's hardware root of trust. Arkora will verify these attestation chains before routing requests, ensuring every API call is processed inside a genuine TEE enclave. This guarantees that even the compute provider cannot read user data, session tokens, or encryption keys in memory.
- Containerized deployment - Arkora's Next.js server and API routes will be packaged as OCI containers deployed to Chutes nodes. The container image hash is included in the TEE attestation, so clients can verify they're talking to the exact published build - no hidden modifications.
- Decentralized routing - Requests will be load-balanced across multiple Chutes miners on subnet 64 via the Bittensor incentive mechanism. Miners are scored on latency, uptime, and attestation validity. Poor performers lose stake; reliable nodes earn TAO emissions.
- Key management - Database credentials and signing keys will be provisioned inside the TEE via sealed storage (keys encrypted to the enclave's identity). Keys are never exposed to the host filesystem or operator. Rotation happens through re-sealing to new enclave measurements.
- Verifiable compute chain - Combined with World ID onchain verification (World Chain) and Hippius decentralized storage (subnet 14), this creates an end-to-end verifiable stack: identity proven onchain, data stored on decentralized storage, and compute executed in attested TEEs - no single trusted party in the critical path.
Arkora exposes a public REST API for accessing verified-human posts, polls, and stats. All data originates from World ID-verified accounts.
Base URL: https://arkora.app/api/v1
Authentication: Include your API key in every request:
X-API-Key: ark_<your-key>| Method | Path | Description |
|---|---|---|
| GET | /v1/posts |
List posts. Params: boardId, type, limit (1-50), cursor |
| GET | /v1/polls |
List polls with live vote counts. Params: boardId, active=true, limit, cursor |
| GET | /v1/boards |
All boards with post counts |
| GET | /v1/stats |
totalPosts, totalPolls, totalVerifiedHumans, totalPollVotes |
All responses follow the format: { success: true, data: [...], nextCursor: "..." | null }
Getting an API key: Open Arkora in World App, go to Settings, scroll to "Developer API", and tap "New API key". You must be a World ID-verified user. Keys are prefixed ark_ and shown once - copy immediately.
Base URL: https://arkora.app/api/v2
v2 endpoints accept dual authentication:
- AgentKit (recommended for AI agents) -
agentkitheader with proof-of-human delegation. Agents get 2x rate limits and access to premium endpoints. - API key fallback - same
X-API-Keyheader as v1.
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /v2/posts |
List posts | AgentKit or API key |
| GET | /v2/polls |
List polls with vote counts | AgentKit or API key |
| GET | /v2/boards |
All boards with post counts | AgentKit or API key |
| GET | /v2/stats |
Platform aggregate stats | AgentKit or API key |
| GET | /v2/sentiment |
Sentiment score per board | AgentKit only |
| GET | /v2/trends |
Trending topics by velocity | AgentKit only |
| GET | /v2/demographics |
Geographic vote distribution | AgentKit only |
Premium endpoints (sentiment, trends, demographics) include 50 free requests per day per human. After that, x402 micropayments apply.
Arkora ships a standalone MCP server so AI agents (Claude, GPT, etc.) can query verified-human data natively.
cd mcp && pnpm install
ARKORA_API_KEY=ark_... npx tsx index.ts # stdio transport
ARKORA_API_KEY=ark_... npx tsx index.ts --sse # SSE on port 3001Available tools: arkora_search_posts, arkora_get_poll_results, arkora_get_sentiment, arkora_get_trends, arkora_get_stats.
app/
api/ API routes (auth, posts, replies, votes, dm, rooms, search, ...)
boards/ Boards list page
post/[id]/ Thread / post detail
rooms/ Rooms discovery + room view
settings/ Settings page
dm/ DM inbox + conversation pages
notifications/ Notifications page
profile/ User profile page
components/
auth/ World ID verification, WalletConnect
compose/ PostComposer, ReplyComposer
dm/ ConversationView, ConversationList
feed/ Feed, ThreadCard, FeedSkeleton
onboarding/ OnboardingScreen
rooms/ RoomsDiscovery, RoomView, RoomCard
search/ SearchSheet (multi-entity search)
settings/ SettingsView, SkinShop, FontShop
thread/ ThreadView, ReplyCard, ReplyTree
ui/ BottomNav, LeftDrawer, BottomSheet, ...
hooks/ Custom React hooks (mentions, search, feed, tips, ...)
lib/
db/ Drizzle schema + per-entity query modules
crypto/ DM encryption (Curve25519 + AES-256-GCM)
i18n/ Translation dictionaries (10 locales) + lazy loader
storage/ Hippius S3 adapter
rateLimit.ts In-memory sliding-window rate limiter
cache.ts Feed cache with TTL
sanitize.ts Input sanitization + mention parsing
serverAuth.ts Session cookie reader
worldid.ts Onchain World ID proof verification
store/
useArkoraStore.ts Global Zustand store
pnpm test # run all tests
pnpm test:watch # watch mode
pnpm test:coverage # coverage report82 unit tests covering input sanitization, rate limiting, E2E DM encryption (Curve25519 + AES-256-GCM), karma tiers, AgentKit auth middleware, and utility functions. Tests run in CI before lint and build.
See QA.md for the full manual testing checklist (80+ test cases across auth, feed, posts, DMs, rooms, monetization, API, and security).
- Push to GitHub and import the repo in the Vercel dashboard.
- Add all environment variables from
.env.example. - Set
NEXT_PUBLIC_APP_IDandAPP_IDto your Worldcoin Developer Portal app ID. - Deploy. Update the Redirect URL in your Developer Portal to match your production domain.
See CONTRIBUTING.md for development setup, branch conventions, and PR requirements.
To report a vulnerability, see SECURITY.md. Do not open public issues for security findings.
MIT - Copyright 2026 Arkora (by Hetark). Free to use, fork, and build on.