Specify docs

JavaScript

Add Specify to any JavaScript app.

Set up with the wizard

npx @specify-sh/wizard --publisher

The wizard runs through the coding agent you already use (Claude Code, Codex etc.). It inspects your codebase, proposes an integration plan and implements it as a reviewable diff.

Prefer to do it by hand? The manual steps below are the same setup.

Manual setup

Runnable example

vanilla-typescript is this guide as a working Vite app.

1. Install the SDK

npm i @specify-sh/publisher-sdk

2. Initialize the client

You will need a publisher key. See Publisher keys.

Create the client once and import it wherever you serve an ad. Use the publisher key via your environment.

lib/specify.js
const specifyPublisherKey = 'spk_123...' // Bring this from your environment

export const specify = new Specify({
  publisherKey: specifyPublisherKey
});

If your site has a consent management platform, connect its targeted-advertising state to the SDK on every page load. The SDK does not persist consent.

cmp.js
import { specify } from './lib/specify';

// Adapt this code to your cookie consent management tool
specify.setCookieConsent(cmp.getConsent().targetedAdvertising);

cmp.onConsentChange((consent) => {
  specify.setCookieConsent(consent.targetedAdvertising);
});

With consent granted, Specify recognises returning visitors across every site in our network, so a placement can fill even when the user has not connected a wallet to your app.

4. Serve an ad

Choose the image format that matches your placement, and pass any wallet address the visitor controls.

Wrap the call so it can run more than once. A first serve often has neither consent nor a wallet to go on, and both usually arrive a moment later.

ad-slot.js
import { specify } from './lib/specify';
import { ImageFormat } from '@specify-sh/publisher-sdk';

let filled = false;

export async function serveAd(wallet) {
  if (filled) return;

  const ad = await specify.serve(wallet ?? null, {
    imageFormat: ImageFormat.LANDSCAPE,
    adUnitId: 'sidebar'
  });

  if (!ad) return;

  filled = true;
  render(ad);
}

specify.onIdentityChange(serveAd);
serveAd();

onIdentityChange() runs when a wallet is registered or consent is granted, so a slot that came back empty tries again on its own. The filled flag keeps it to one ad: asking again over an ad already on the page would replace what the visitor is looking at.

Available image formats and the fields returned in the ad can be found in the Browser SDK reference.

Network requirements

The SDK sends ad requests to https://spfsrv.com. After consent, the browser sends these requests with credentials. If your site has a Content Security Policy, add https://spfsrv.com to connect-src.

Send SDK traffic straight to Specify. Do not proxy it through your backend because a proxy strips cookies and geolocation information.

Next steps

On this page