Quickstart: Algorithms DSL
This example shows how to use the Algorithms DSL (algo-dsl) to build a Polymarket prediction market feed. It demonstrates the full pipeline: search → features → scoring → ranking.
The guide starts with a basic unpersonalized feed (no wallet required), then shows how to add personalization with a Polymarket wallet.
Install
npm install algo-dsl dotenvThis installs:
- algo-dsl — Embed Studio backend client for search, features, scoring, and ranking
- dotenv — Loads environment variables from
.env
Configure
Create a .env file with your API key:
EMBED_API_KEY=your-mbd-api-key| Variable | Description |
|---|---|
EMBED_API_KEY | Your Embed API key from the Console (starts with mbd-) |
That's all you need to get started. A Polymarket wallet address is only needed if you want personalization (see Adding Personalization below).
Basic Feed (No Wallet Required)
This builds a ranked feed of active Polymarket markets using search, features, and ranking — no wallet needed.
1. Initialize the SDK
import 'dotenv/config';
import { StudioConfig, StudioV1 } from 'algo-dsl';
const config = new StudioConfig({ apiKey: process.env.EMBED_API_KEY });
const mbd = new StudioV1({ config });2. Search (candidate retrieval)
const candidates = await mbd.search()
.index("polymarket-items")
.size(100)
.include()
.numeric("volume_1wk", ">=", 10000)
.exclude()
.term("closed", true)
.term("price_under05_or_over95", true)
.execute()
mbd.addCandidates(candidates);- Index:
polymarket-items— prediction markets - Include filter: weekly volume ≥ $10k
- Exclude filters: closed markets and extreme prices (< 5% or > 95%)
3. Features (enrichment)
const features = await mbd.features("v1").execute()
mbd.addFeatures(features);Computes ML signals like topic_score for each candidate. Without a user context set, user-specific features (like user_affinity_score) will be zero — that's fine for an unpersonalized feed.
4. Ranking (final ordering)
const ranking = await mbd.ranking()
.sortingMethod('sort')
.sortBy('topic_score', 'desc')
.execute()
mbd.addRanking(ranking);Sorts candidates by topic relevance. For an unpersonalized feed, a simple sort works well.
5. Output
const feed = mbd.getFeed();
for (const item of feed.slice(0, 10)) {
console.log(item._id, item._source.question, item._ranking_score);
}Run it:
node polymarket.jsYou should see the top 10 Polymarket markets ranked by topic relevance.
Adding Personalization
To personalize results for a specific user, add a wallet address and three extra steps: forUser, boost search, and scoring.
Add the wallet to your .env:
EMBED_API_KEY=your-mbd-api-key
POLYMARKET_WALLET=0xYourPolymarketWalletAddress1. Set user context
const polymarketWallet = process.env.POLYMARKET_WALLET?.toLowerCase().trim();
const config = new StudioConfig({ apiKey: process.env.EMBED_API_KEY });
const mbd = new StudioV1({ config });
// Tell the SDK which user to personalize for
mbd.forUser("polymarket-wallets", polymarketWallet);Important:
forUsertakes two arguments:
- User profile index — the index where the user's profile lives (
polymarket-walletsfor Polymarket,farcaster-itemsfor Farcaster). This is NOT the items index.- User ID — the user's identifier within that index (e.g. a wallet address for Polymarket, a FID for Farcaster).
If you use the wrong index (e.g.
polymarket-itemsinstead ofpolymarket-wallets), features likeuser_affinity_scorewill return empty or zero.
2. Search with personalized boosts
const candidates = await mbd.search()
.index("polymarket-items")
.includeVectors(true)
.include()
.numeric("volume_1wk", ">=", 10000)
.exclude()
.term("closed", true)
.term("price_under05_or_over95", true)
.boost()
.groupBoost("polymarket-wallets", "ai_labels_med", polymarketWallet, "label", 1, 5, 10)
.groupBoost("polymarket-wallets", "tags", polymarketWallet, "tag", 1, 5, 10)
.execute()
mbd.addCandidates(candidates);The .boost() section is what makes this personalized — it looks up the user's label and tag preferences from their wallet profile and boosts matching markets.
includeVectors(true)— needed for semantic diversity in rankinggroupBoost— dynamically boosts items matching the user's top labels and tags
3. Features (enrichment)
const features = await mbd.features("v1").execute()
mbd.addFeatures(features);With forUser set, features now include personalized signals like user_affinity_score alongside topic_score.
4. Scoring (reranking model)
const scores = await mbd.scoring()
.model("/scoring/ranking_model/polymarket-rerank-v1")
.execute()
mbd.addScores(scores, "ranking_model_polymarket_rerank_v1");The Polymarket rerank model understands user-market relationships and produces a holistic relevance score.
5. Ranking (final ordering)
const ranking = await mbd.ranking()
.sortingMethod('mix')
.mix("topic_score", 'desc', 40)
.mix("user_affinity_score", 'desc', 40)
.mix("rerank_polymkt1", 'desc', 20)
.diversity('semantic')
.lambda(0.5)
.horizon(20)
.limitByField()
.every(10)
.limit("cluster_1", 1)
.execute()
mbd.addRanking(ranking);- Mix weights: topic (40%), user affinity (40%), rerank model (20%)
- Semantic diversity: spreads similar items apart (lambda 0.5, horizon 20)
- Field limits: max 1 item per
cluster_1value per 10 results
6. Output
const feed = mbd.getFeed();
for (const item of feed.slice(0, 10)) {
console.log(item._id, item._source.question, item._ranking_score);
}Pipeline Overview
┌─────────────────────────────────────┐
│ Basic (no wallet) │
│ │
API key ──→ [Search] ──→ [Features] ──→ [Ranking: sort] ──→ Feed
│ │
└─────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Personalized (with wallet) │
│ │
API key ──→ forUser ──→ [Search + boost] ──→ [Features] ──→ [Scoring] ──→ [Ranking: mix + diversity] ──→ Feed
+ │ │
wallet └─────────────────────────────────────────────────┘
What's Next
This quickstart builds a feed pipeline in code. To deploy it for production serving:
- Save as an algorithm — use the Console or
POST /deploy/algosto save your pipeline code - Create a feed config — bundle your algorithm with cache settings, weights, and fallbacks. See Feed Configs
- Serve in production — call
POST /deploy/servewith yourconfig_id. See Serving
Or explore the pipeline stages in depth:
- [Search](../Building Algorithms/search) — filters, boost, semantic search, all 4 indices
- [Features](../Building Algorithms/algo-features) — ML enrichment and personalization signals
- [Scoring & Ranking](../Building Algorithms/algo-scoring-ranking) — reranking models, sort methods, diversity
- [Vibecode a Polymarket Feed](../Getting Started/vibecoding-with-embed) — full Next.js app with charts and filtering
Updated 9 days ago
