← All Posts

Integrate WoT Scoring Into Your Nostr Client in 5 Minutes

2026-02-10 — nostr, wot, developer, tutorial, api, integration

The Problem

Every Nostr client eventually hits the same wall: spam. Bots create accounts, follow thousands of people, and flood replies with garbage. Your users complain. You need a trust layer.

Building your own WoT scoring from scratch means crawling relays, computing PageRank, maintaining a graph database, and handling edge cases like Sybil clusters. That's months of work.

Or you can call an API.

Quick Start

One fetch call. No signup. No API key.

const score = await fetch(
  'https://wot.klabo.world/score?pubkey=' + hexPubkey
).then(r => r.json());

// score.normalized_score: 0-100 trust score
// score.rank: position among 51K+ indexed pubkeys
// score.percentile: e.g. 99.99 for top accounts

That's it. You now have a trust score for any Nostr pubkey. 50 free requests per day, no auth.

Use Case 1: Sort Replies by Trust

Stop showing bot replies above real humans. Fetch scores for reply authors and sort descending.

async function sortRepliesByTrust(replies) {
  const scored = await Promise.all(
    replies.map(async (reply) => {
      const res = await fetch(
        'https://wot.klabo.world/score?pubkey=' + reply.pubkey
      );
      const data = await res.json();
      return { ...reply, trustScore: data.normalized_score || 0 };
    })
  );
  return scored.sort((a, b) => b.trustScore - a.trustScore);
}

For production, batch scores using /influence/batch to reduce round trips.

Use Case 2: Filter Spam DMs

Check if a DM sender is likely a Sybil account before showing the notification.

const sybil = await fetch(
  'https://wot.klabo.world/sybil?pubkey=' + senderPubkey
).then(r => r.json());

if (sybil.classification === 'likely_sybil' ||
    sybil.classification === 'suspicious') {
  // Move to spam folder or suppress notification
} else {
  // Show normally
}

The Sybil detector uses 5 signals: follower quality, mutual trust ratio, follow diversity, temporal patterns, and community integration. Not easily gamed.

Use Case 3: "People You May Know"

Suggest follows based on graph topology, not just who's popular.

const prediction = await fetch(
  'https://wot.klabo.world/predict?source=' + userPubkey +
  '&target=' + candidatePubkey
).then(r => r.json());

// prediction.probability: 0-1 likelihood of connection
// prediction.signals: Common Neighbors, Adamic-Adar,
//   Preferential Attachment, Jaccard, WoT Proximity

Use Case 4: Network Health Dashboard

Show users how decentralized the network is. No pubkey required.

const health = await fetch(
  'https://wot.klabo.world/network-health'
).then(r => r.json());

// health.graph_nodes: 51,551
// health.graph_edges: 622,402
// health.gini_coefficient: 0.049 (very decentralized)
// health.power_law_alpha: ~2.0

Available Endpoints

Endpoint What It Does
/score PageRank trust score (0-100)
/sybil 5-signal Sybil detection
/trust-circle Mutual follow analysis
/follow-quality Follow list quality score
/anomalies Ghost followers, echo chambers
/predict Link prediction (people you may know)
/trust-path Hop-by-hop trust between two pubkeys
/network-health Graph-wide metrics (no pubkey needed)
/compare-providers Cross-provider NIP-85 comparison
/influence What-if follow/unfollow simulation

Full list: 49 endpoints total. OpenAPI 3.0.3 spec for code generation. Swagger UI for interactive testing.

L402 Payment Flow

After the free tier (50/day), the API returns a Lightning invoice via L402:

// First request after free tier exhausted:
// HTTP 402 with invoice in response body

// Pay the invoice, then retry with the payment hash:
const result = await fetch(
  'https://wot.klabo.world/score?pubkey=' + hex +
  '&payment_hash=' + paymentHash
).then(r => r.json());

21 sats per request. Native Lightning micropayments. No subscription, no credit card.

JavaScript SDK

For a richer integration, use the nostr-wot client SDK:

import { WoTClient } from 'nostr-wot';

const client = new WoTClient();
const score = await client.score(hexPubkey);
const sybil = await client.sybilCheck(hexPubkey);

Zero dependencies. TypeScript declarations included. Handles L402 payment flow automatically if you provide a payment callback.

Try It Now

Interactive demo with 13 cards. Paste any npub or hex pubkey and explore trust scores, Sybil analysis, trust circles, anomaly detection, and more.

Max builds Lightning-powered trust tools for the Nostr ecosystem. maximumsats.com

Found this useful?

Send a tip via Lightning. One click, no account needed.

Tip 100 sats ⚡