Start a campaign
Open the campaign portal, sign in with a verified email, and review the live market before setting your bid.
- Write a plain 3-80 character sponsor line.
- Add an optional HTTPS destination and brand name.
- Choose a price per block and number of blocks. One block is 1,000 verified impressions.
- Complete Stripe Checkout. The campaign activates after payment verification.
Write the sponsor line
The message appears as one terminal-native line. Keep it specific, useful, and understandable without rich formatting.
✦ Sponsor · Ship reliable webhooks with AcmeAds must identify a real product or service, make substantiated claims, and comply with the ad content policy. Destinations must use HTTPS.
Ways to pay
Dawdlo prices per outcome, per click, or per impression. Set pricing_model when you create a campaign.
- CPA (recommended) —
pricing_model:"cpa". You pay only when a click converts, confirmed by your own server-to-server postback. The impression is served at no cost; the developer earns a cash cashback share of each conversion. You are never billed for attention that does not convert. - CPC —
pricing_model:"cpc". You pay a fixedcpc_usdeach time a developer clicks the sponsor line; the impression is served at no cost. The developer earns $0 on a click (they earn on impressions and conversions, never on their own click), so there is no click-fraud incentive. - CPM (brand) —
pricing_model:"cpm"(default). You pay per verified impression. Generic ads compete on bid and clear at second-price (the runner-up’s bid). This is the capped brand-awareness layer. - Hybrid — pay CPM for the impression and CPA on conversion.
Ads also come in two placement tiers, split by attention and decided by ad_kind — and the two never overlap:
- Generic — ambient surfaces (
ad_kind:"generic"). The impression tier. Runs run-of-network across the status line and spinner, competing on bid and clearing at second-price. Generic ads can price CPM, CPA, CPC, or hybrid. - Resonance — in-flow surfaces (
ad_kind:"resonant"). The in-flow tier. Serves only where the agent is speaking — inline in its reply (conversation) or voiced during a real wait (agent wait) — matched on the developer’s own device to what they are asking about or building. It shows only on a genuine match, and their working context never leaves their machine. Relevance, not bid, picks the winner, so it pays first-price: exactly your bid, down to the floor. Setmatch_intent(and optionalmatch_keywords); CPM only for now.
You cannot mix them: a resonant campaign serves only on the in-flow surfaces (conversation, agent_wait), and the ambient surfaces serve only generic ads. Crossing tiers — an ambient surface for a resonant campaign, or an in-flow surface for a generic one — is rejected at create time.
Conversion tracking
Every click redirect carries a signed attribution token on the query string as dwref — on every pricing model, so CPM and CPC campaigns can attribute conversions too. Read it on your landing page, store it against the user you create, and post it back when that user signs up or activates.
# 1. Your landing page receives: https://example.com/signup?dwref=<token>
# 2. When the user converts, post back from your server:
curl -sS "$DAWDLO_HOST/api/v1/conversions" \
-H "Authorization: Bearer $DAWDLO_ADV_KEY" \
-H "Content-Type: application/json" \
-d '{
"dwref":"<token from the landing page>",
"dedupe_key":"your-user-id",
"event_type":"signup"
}'On a CPA campaign the postback charges your CPA once and credits the developer cashback. It is idempotent: replaying the same dwref (or dedupe_key) is a no-op, so retries are safe. A conversion is never billed beyond your remaining budget or balance.
Prefer not to hand-roll this? The official SDK wraps capture and postback for you.
SDK (@dawdlo/sdk)
The advertiser SDK wraps the whole dwref flow — capture on your landing page, then post the conversion back — plus campaign management, so you never hand-roll HTTP or auth. Node (ESM + CJS) and a browser drop-in, zero runtime dependencies.
npm install @dawdlo/sdk1. Capture the token on your landing page. Server-side with Express, or the browser drop-in if you have no server capture:
import { expressCapture, readStoredDwref } from '@dawdlo/sdk';
app.use(expressCapture()); // sets a dwref cookie from ?dwref
// — or, no server? drop this on the landing page —
// <script src="https://unpkg.com/@dawdlo/sdk/dist/dawdlo-capture.global.js"></script>2. Report the conversion when the visitor signs up. Idempotent on dedupeKey; an expired or forged token throws a typed DawdloApiError:
import { DawdloAdvertiser, readStoredDwref } from '@dawdlo/sdk';
const dawdlo = new DawdloAdvertiser({ apiKey: process.env.DAWDLO_ADV_KEY });
await dawdlo.reportConversion({
dwref: readStoredDwref(req),
dedupeKey: user.id,
eventType: 'signup',
});Manage and track campaigns with the same client:
await dawdlo.createCampaign({
creativeText: 'Acme — ship faster',
url: 'https://acme.dev',
budgetUsd: 500,
pricingModel: 'cpc', // or 'cpa' | 'cpm' | 'hybrid'
cpcUsd: 0.5,
});
const { balanceUsd, campaigns } = await dawdlo.listCampaigns();Impression bidding (CPM)
CPM bids are stated in USD per 1,000 verified impressions. Ambient (generic) floors reflect targeted developer attention: $20 CPM status line, $30 spinner. The Resonance tier (conversation, agent_wait) prices separately as a low fixed-rate product with a larger platform cut.
- The highest eligible campaign wins each auction.
- The winner pays the runner-up bid plus one micro-dollar per impression, never more than its own bid.
- A served response is not billable. The line must remain visible while the agent is active for at least four seconds.
- Delivery stops when a campaign is paused, exhausted, unfunded, or ineligible for the requesting device.
Frequency caps limit a device to six views from one campaign and 90 total sponsored views per hour.
Contextual targeting
API campaigns can provide comma-separated context tags. Empty targeting matches all inventory; otherwise at least one tag must match.
claude-code,agent,linux,darwin,windowsClients may also send model and project tags. Target context, not people: Dawdlo does not require behavioral profiles.
Advertiser API
Create an advertiser credential from your signed-in account. Keep the advk_ value in a secret manager and send it as a bearer token.
export DAWDLO_HOST=https://api.example.com
export DAWDLO_ADV_KEY=advk_...
curl -sS "$DAWDLO_HOST/api/v1/campaigns" \
-H "Authorization: Bearer $DAWDLO_ADV_KEY" \
-H "Content-Type: application/json" \
-d '{
"creative_text":"Ship reliable webhooks with Acme",
"url":"https://example.com/developers",
"brand_name":"Acme",
"pricing_model":"cpa",
"cpa_usd":50,
"cashback_pct":55,
"budget_usd":1000,
"targeting":"claude-code,linux"
}'For a pay-per-click campaign, set "pricing_model":"cpc" and "cpc_usd":0.5 instead of the CPA fields. Use GET /api/v1/campaigns to inspect balance, spend, confirmed views, pending views, clicks, conversions, and status. Pause or resume with PATCH /api/v1/campaigns/:id. Report conversions with POST /api/v1/conversions (see Conversion tracking).
Most advertisers should use the official SDK instead of calling these endpoints directly.
Campaign states
pendingWaiting for verified payment.activeEligible to enter auctions.pausedStopped by the advertiser or platform.exhaustedBudget cannot cover another view.Public market labels such as LIVE, QUEUED, and COMPLETE describe market position rather than editable campaign state.