Specify docs

Recognising returning visitors

Serve ads after a wallet disconnects.

Recognising a returning visitor is particularly valuable for publishers whose users sometimes have an active wallet connection and sometimes don't, which describes most dapps. This is most common when the user returns to your site after a period of inactivity.

Without a way to recognise them, those post-disconnection impressions won't see ads at all, because we won't have a wallet address to identify the user.

You can provide us permission to set a cookie with setCookieConsent(true) to greatly increase the percentage of users that see ads. To do this, you need to get consent from the user via a Consent Management Platform (CMP) or simply a cookie banner.

This only applies in a browser. Node.js SDK always needs the wallet addresses passed to serve().

Call setCookieConsent() whenever the visitor's choice changes, and again on every page load. The SDK never stores the answer, so your consent tool stays the only source of truth.

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

// Adapt this code to your cookie consent management tool
cmp.onConsentChange((consent) => {
  specify.setCookieConsent(consent.targetedAdvertising);
});

Serve without a wallet

Once consent is granted, a serve with no address behind it can still fill: Specify resolves the visitor from the cookie alone.

Most placements do not know whether a wallet is connected, and they do not have to. serve() accepts null in the address position, so one call covers both cases:

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

// A connected wallet is used if there is one. If not, the cookie is.
const ad = await specify.serve(getConnectedWallet() ?? null, {
  imageFormat: ImageFormat.LONG_BANNER,
  adUnitId: 'article-footer'
});

if (ad) render(ad);

Where the placement has no address in scope at all, drop the first argument: serve({ imageFormat }).

Keep passing wallets when you have them

The cookie does not replace wallet addresses, it covers the gap when you have none. Pass them whenever a wallet is connected: each serve that carries one strengthens the link the cookie later resolves.

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

// On connect, so every later serve() includes it
onWalletConnect((address) => specify.identify(address));

See Consent for the full method reference.

On privacy

Specify sets one cookie, on our own domain. Because it is set while the visitor is on your site rather than ours, it is a third-party cookie.

Without consent we neither read nor set it, and ads still serve against the wallet addresses you pass.

We do not use browser fingerprinting.

On this page