clue
한국어
로그인시작하기
문서

문서

광고하고, 매체를 등록하고, 클루를 읽는 데 필요한 모든 것이에요. 광고주는 캠페인과 클루로 시작해요. 매체는 매체 등록 하나와 설치 스니펫 하나로 시작해요. 에이전트는 정책 페이지로 시작해요. 전부 REST API로도 할 수 있어요.

광고주

광고주 계정에는 선불 잔액, 캠페인, 클루가 있어요. 캠페인은 과금 방식, 입찰가, 예산, 매칭 규칙을 정해요. 클루는 에이전트가 받는 기록이에요. 아래 모든 일은 API 키로도 할 수 있어요.

  1. 잔액을 충전해요. 첫 충전은 $50 이상이고 Stripe를 통해 카드로 결제해요.
  2. 캠페인을 만들어요. CPC·CPA·CPM 중 하나를 고르고, 최대 입찰가와 예산을 정하고, 언제 검토돼야 하는지 규칙을 정해요.
  3. 자신의 언어로 클루를 써요. clue가 약 1분 안에 정책 심사를 하고 20개 언어로 번역해요.

매칭 규칙

비우면 전 세계예요. 국가는 에이전트의 네트워크 위치 또는 매체가 알려주는 값에서 와요. 에이전트가 요청한 언어예요. 비우면 모든 언어예요. 클루는 자동 번역되므로 이 규칙은 노출 범위만 제한해요. 매체가 선언한 카테고리와 에이전트가 작업 중인 페이지·작업 문맥에 매칭돼요. 비우면 모든 유형이에요. 학습용 크롤러는 클루에 거의 행동하지 않고, 브라우징 에이전트·API 클라이언트·MCP 클라이언트는 보통 행동해요. 에이전트가 하려는 일이에요. 매체나 에이전트가 선언하거나 문맥에서 추론해요. 비우면 모든 의도예요. 기업, 소비자, 또는 모두예요. clue는 18세 미만 사용자에게 클루를 매칭하지 않아요.

결과 보고

에이전트가 클루를 따라가면 목적지 URL에 ?clue_id=<id>를 붙여 보내요. 그 방문이 가입, 구매, 예약, API 호출로 이어지면 그 id를 clue에 POST해요. CPA 캠페인은 그 순간 청구되고, CPC·CPM 캠페인은 리포트에 액션만 기록돼요.

POST https://clue.ad/v1/conversions
Authorization: Bearer clue_…
Content-Type: application/json

{"click_id": "sv_…", "kind": "signup", "value_usd": 49, "external_id": "order_123"}

매체와 에이전트 개발자

매체는 내가 소유한 웹사이트, API, MCP 서버, 에이전트예요. 각 매체에는 키, 하나 이상의 슬롯(슬롯은 응답의 형식과 스타일을 고정해요), 제어, 분석이 있어요. 소유권을 한 번 인증하면 수익이 시작돼요.

  1. 웹사이트, API, MCP 서버, 에이전트를 등록하고 메타 태그나 파일로 소유권을 인증해요.
  2. 슬롯을 만들고 표면이 쓰는 형식을 골라요. JSON, Markdown, 텍스트, HTML, llms.txt, MCP예요.
  3. 태그, 미들웨어, API 호출을 설치해요. 클루가 매칭되기 전이라도 첫 요청부터 에이전트 분석이 시작돼요.

서버 측 연동은 User-Agent와 헤더로 에이전트를 식별하고, clue에 매칭을 요청한 뒤, 응답이 서버를 떠나기 전에 HTML·Markdown·JSON에 블록을 추가해요. 사람 방문자는 원래 응답을 그대로 받아요.

JavaScript를 실행하는 브라우징 에이전트용이에요. 페이지에 표시된 <aside>와 JSON-LD를 추가해요. 사람에게는 접힌 작은 안내만 보여요.

<script async src="https://clue.ad/tag.js" data-site="site_YOUR_KEY" data-unit="unit_YOUR_UNIT" data-lang="auto" data-max="2"></script>
<!-- optional: where the block should go -->
<div data-clue-slot></div>
// npm i @clue-ad/node   (or copy sdk/node/clue.mjs from the docs)
import { clueMiddleware } from '@clue-ad/node';

// Express / Connect
app.use(clueMiddleware({ site: 'site_YOUR_KEY', unit: 'unit_YOUR_UNIT', base: 'https://clue.ad' }));

// Next.js (app/route.ts or middleware.ts)
import { withClue } from '@clue-ad/node/next';
export default withClue({ site: 'site_YOUR_KEY' })(handler);

// What it does: detects agents (User-Agent + headers), calls https://clue.ad/v1/serve,
// injects <aside data-clue> before </body> for HTML, a "sponsored" array for JSON, a block for Markdown.
// Humans get the untouched response.
# pip install clue-ad   (or copy sdk/python/clue.py)
from clue import ClueMiddleware

# FastAPI / Starlette
app.add_middleware(ClueMiddleware, site="site_YOUR_KEY", unit="unit_YOUR_UNIT", base="https://clue.ad")

# Flask
from clue import flask_clue
flask_clue(app, site="site_YOUR_KEY")

# Django: add "clue.django.ClueMiddleware" to MIDDLEWARE and set CLUE_SITE = "site_YOUR_KEY"
// go get github.com/clue-ad/clue-go   (or copy sdk/go/clue.go)
import clue "github.com/clue-ad/clue-go"

handler := clue.Wrap(mux, clue.Config{Site: "site_YOUR_KEY", Unit: "unit_YOUR_UNIT", Base: "https://clue.ad"})
http.ListenAndServe(":8080", handler)
// Cloudflare Worker in front of your origin (copy sdk/cloudflare/worker.js)
export default {
  async fetch(req, env, ctx) {
    const res = await fetch(req);
    return injectClue(req, res, { site: 'site_YOUR_KEY', unit: 'unit_YOUR_UNIT', base: 'https://clue.ad' });
  }
}
<?php // copy sdk/php/clue.php; WordPress: add to functions.php or use as a mu-plugin
require_once 'clue.php';
clue_start(['site' => 'site_YOUR_KEY', 'unit' => 'unit_YOUR_UNIT', 'base' => 'https://clue.ad']);
// buffers the HTML response and appends the sponsored block for agents only
# Server-side, any language. Forward the visitor's User-Agent so clue can tell agents from humans.
GET https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=json&lang=<bcp47>&country=<iso2>&url=<page url>&context=<page title / task text>&intent=<research|compare|purchase|booking|coding|data|integration|support|writing>
User-Agent: <visitor's user agent>

# Response (200): {"sponsored":true,"disclosure":"…","clues":[…]}  — empty clues for humans
# Formats: json | markdown | text | html | llms | mcp   ·   Test: &test=1
# Add to your llms.txt (agents that read llms.txt follow the link; nothing else changes)
## Sponsored
- [Sponsored clues for this site](https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=llms)

# Or fetch and inline the lines server-side when generating llms.txt:
curl -s "https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=llms&lang=en"
// Inside your own MCP server: append clue's result to relevant tool responses.
const r = await fetch('https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=mcp&lang=' + lang + '&q=' + encodeURIComponent(taskText), { headers: { 'x-agent-type': 'mcp_client' } });
const sponsored = await r.json(); // { sponsored: true, disclosure, clues: [...] }
return { content: [{ type: 'text', text: JSON.stringify({ result, sponsored }) }] };
// Agent developers: ask clue directly from your agent loop (you are the publisher and earn 65%).
const r = await fetch('https://clue.ad/v1/discover', {
  method: 'POST', headers: { 'content-type': 'application/json', 'x-agent-type': 'api_client', 'x-agent-name': 'my-agent' },
  body: JSON.stringify({ task: userTask, lang: userLang, country: userCountry, site: 'site_YOUR_KEY', max: 3 })
});
const { disclosure, clues } = await r.json();
// Show clues to your model as clearly-labelled sponsored options; report outcomes to clue.outcome_url.

제어

1,000건당 이 금액보다 적게 벌어들이는 클루는 건너뛰어요. 0으로 두면 최저가가 없어요. 유료 클루가 매칭되지 않을 때 돌려줘요. title, summary, url을 담은 JSON이에요. 청구도 지급도 없어요. 어떤 요청에든 &test=1을 붙이면 청구도 지급도 되지 않는, 명확히 표시된 테스트 클루를 받아요.

카테고리

developer_toolsai_mlcloud_infradata_analyticssecurityproductivitycommunicationecommerceretail_productsfinance_fintechinsurancetravelhospitalityfood_deliveryreal_estateautomotivehealth_wellnesseducationlegalhr_recruitingmarketing_salesmedia_entertainmentgamingnewssciencegovernment_publicnonprofithome_serviceslogisticsmanufacturingenergytelecomconsumer_appsother

에이전트

에이전트는 계정이 필요 없어요. 정책 페이지가 클루의 형식, 고지, 팔로우 리다이렉트, 결과 보고, 그리고 clue에 직접 묻는 방법을 설명해요. AI 에이전트를 위한 안내: 클루를 읽는 방법.

clue REST API

모든 엔드포인트는 JSON을 써요. API 키 페이지의 키로 Authorization: Bearer <api key> 헤더를 보내 인증해요. discover와 serve 엔드포인트는 공개이며 대신 매체 키로 식별돼요.

MethodPathAuthNotes
GET/v1/discoverpublicAgent intent → clues. q/task, lang, country, intent, max, format, site (optional integration key to credit an agent developer).
POST/v1/discoverpublicSame as GET with a JSON body: {"task":"…","lang":"ko","country":"KR","intent":"purchase","max":3}
GET|POST/v1/servepublicPublisher serve. site (required), unit, format (json|markdown|text|html|llms|mcp), max, style, lang, country, url, title, context, intent, audience, session, test=1, humans=1
GET/c/:tokenpublicFollow redirect → destination URL + ?clue_id=. Charged once for CPC.
POST/v1/outcome/:clue_idpublic{"outcome":"useful|not_useful|used|purchased"} — agent outcome. used/purchased also record an action.
POST/v1/conversionsadvertiser key{"click_id":"sv_…","kind":"signup","value_usd":49,"external_id":"…"} — report an action for a follow.
POST/mcppublicMCP Streamable HTTP (JSON-RPC 2.0): initialize, tools/list, tools/call (discover_clues, report_outcome).
GET/v1/mekeyAccount, balances, platform languages.
GET|POST/v1/campaignskeyList / create campaigns. Body: name, pricing_model (cpc|cpa|cpm), bid_usd, daily_budget_usd, total_budget_usd, start_at, end_at, countries[], languages[], categories[], keywords[], negative_keywords[], agent_types[], agent_vendors[], intents[], audience_kind, audience_ages[], dayparting[], weekdays[], frequency_cap, include_house
GET|PATCH/v1/campaigns/:idkeyRead (with clues) / update. PATCH {"status":"paused"} pauses.
POST/v1/campaigns/:id/clueskeyCreate a clue. Body: advertiser_name, title, summary, details, capabilities[], pricing, cta, landing_url, docs_url, mcp_url, llms_txt_url, api_base_url, categories[], source_lang
PATCH/v1/clues/:idkeyUpdate a clue (re-reviewed, re-translated) or {"status":"paused"|"active"}.
GET/v1/clues/:id/translationskeyAll translations of a clue.
GET/v1/reports/advertiserkeyby=day|country|lang|agent_type|agent_vendor|campaign_id|clue_id|site_id|format, days=30
GET/v1/reports/publisherkeyby=day|country|lang|agent_type|agent_vendor|site_id|unit_id|format|advertiser_id, days=30
GET/v1/siteskeyYour integrations with totals.
GET/.well-known/agent-ads.jsonpublicDiscovery document for the agent-ads convention.
# Create a campaign and a clue with the API (an agent can do this too)
curl -X POST https://clue.ad/v1/campaigns -H "Authorization: Bearer clue_…" -H "content-type: application/json" -d '{
  "name": "GPU cloud — Korea", "pricing_model": "cpc", "bid_usd": 0.40, "daily_budget_usd": 50,
  "countries": ["KR","JP"], "categories": ["cloud_infra","ai_ml"], "keywords": ["gpu","b300","h100","cluster"],
  "agent_types": ["browsing_agent","api_client","mcp_client"], "intents": ["purchase","compare","coding"]
}'

curl -X POST https://clue.ad/v1/campaigns/123/clues -H "Authorization: Bearer clue_…" -H "content-type: application/json" -d '{
  "advertiser_name": "Acme Cloud", "title": "B300 GPU instances in Seoul", "source_lang": "en",
  "summary": "On-demand B300 GPU instances, immediate availability, Seoul region.",
  "capabilities": ["8–64 GPU clusters", "InfiniBand", "per-hour billing"], "pricing": "$3.20/GPU/hour, min 8 GPUs",
  "cta": "Request a quote", "landing_url": "https://acme.example/gpu", "docs_url": "https://acme.example/docs"
}'

# Agent: discover
curl -X POST https://clue.ad/v1/discover -H "content-type: application/json" -H "x-agent-name: my-agent" -d '{"task":"find a B300 GPU cluster in Korea next week","lang":"en","country":"KR"}'