Docs
One slot, on your page, in one paste.
You already sell sponsorships by hand. This replaces the part where you edit your HTML every time the sponsor changes, and keeps the look you already have.
Drop in the tag
One container where the slot goes, and the script once in the page. The container is yours: move it, size it, style it.
<div data-sb-slot="footer" data-sb-site="yoursite.com"></div>
<script src="https://sponsorslot.dogfooded.com/dfu/s.js" async></script>data-sb-slot is the slot's name, as you see it in your console. data-sb-site is the site you registered: you can leave it out on that exact domain, and need it on a subdomain. The script sets no cookies and measures nothing but its own visibility.
Works the same on a single-page app, Next.js included: a container that shows up after a client-side navigation is filled as soon as it lands in the page.
It already looks like your page
Every value in the slot is a CSS variable whose default inherits from your page: the typeface, the text color, and a border derived from that same color. You get this without configuring anything.
Layouts
A layout decides where the logo, the text and the label go. It does not decide colors or borders: that is theming, and the two compose.
<div data-sb-slot="footer"></div>Write it like a prop, on the container itself. Nothing is stored on our side, so three slots on the same page can use three layouts.
<div data-sb-slot="footer" data-sb-variant="stack"></div>Whichever one you pick, we render the sponsored label ourselves. An impression is only counted when that label is readable, so a layout you did not build never quietly drops your numbers.
Arrow
An arrow in the bottom right corner tells visitors the whole card is a link. It is off by default: add the attribute to the container to turn it on.
<div data-sb-slot="footer"></div><div data-sb-slot="footer" data-sb-arrow></div>It takes its color from the slot. Size it with --sb-arrow-size and soften it with --sb-arrow-opacity.
Hover
Give the card a response when a visitor points at it, or reaches it with the keyboard. Hover the preview to try each one.
<div data-sb-slot="footer" data-sb-arrow></div>Put it on the slot, or once on a wrapper to cover every slot inside.
<div class="sponsors" data-sb-hover="lift">
<div data-sb-slot="place-1"></div>
<div data-sb-slot="place-2"></div>
</div>Each effect uses your text color, and --sb-hover-color sets another one. With the arrow on, it moves toward the corner too. Visitors who asked their system for less motion get the effect without the movement.
Grid
One container per slot, in your own grid.
<div class="sponsors">
<div data-sb-slot="place-1" data-sb-variant="stack"></div>
<div data-sb-slot="place-2" data-sb-variant="stack"></div>
<div data-sb-slot="place-3" data-sb-variant="stack"></div>
</div>
<style>
.sponsors { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px }
</style>List
One container per slot, stacked.
<div data-sb-slot="place-1" data-sb-variant="list"></div>
<div data-sb-slot="place-2" data-sb-variant="list"></div>
<div data-sb-slot="place-3" data-sb-variant="list"></div>Carousel
Put your slots inside one container and give it an interval in seconds. We lay them out in a row that scrolls sideways, and move to the next sponsor on every beat. Hover the preview and it waits for you.
<div data-sb-carousel="5" data-sb-hover="lift">
<div data-sb-slot="place-1" data-sb-variant="stack"></div>
<div data-sb-slot="place-2" data-sb-variant="stack"></div>
<div data-sb-slot="place-3" data-sb-variant="stack"></div>
</div>| When | The carousel |
|---|---|
| Every interval | moves to the next card |
| After the last card | scrolls back to the first one |
| A mouse over it, a finger on it, keyboard focus inside | waits, then gives a full interval once the visitor leaves |
| Off screen, or the tab in the background | waits, so the first sponsor is the first one people see |
| A visitor who asked for less motion | stays put and scrolls by hand |
The width of a card and the space between two are tokens, and 0 gives you a carousel that moves only when visitors scroll it.
[data-sb-carousel] { --sb-carousel-width: 300px; --sb-carousel-gap: 24px }Each card is still its own slot, measured on its own: it counts once it has spent a full second in view. That is why the interval shares the 4 second floor of rotation. Keep each card at least 120 px wide.
Rotation
Put several slot names on one container and give it an interval in seconds. The slot moves from one sponsor to the next.
<div data-sb-slot="place-1,place-2,place-3" data-sb-rotate="1"></div>Each name stays a distinct slot. Rotation shares a position, it does not turn one slot into ten.
Each one is measured on its own, so a slot shown one turn in three reports the impressions it actually got, not a third of the page.
The interval has a floor of 4 seconds.
An impression needs 1 continuous second on screen. Rotating faster than that would mean no slide ever reaches the threshold: a perfect looking carousel, counting nothing. Ask for less and we hold the floor.
Animations
Rotation uses a cross fade by default. Add data-sb-anim to change it, on a rotating slot or on a static one you want to appear rather than pop in.
<div data-sb-slot="place-1,place-2" data-sb-anim="dissolve" data-sb-rotate="8"></div>Nothing moves unless you ask: without the attribute the slot appears the way it always has. And a visitor who asked their system for less motion gets none of it, the content still changes.
Skins
Three ready-made sets of tokens. Copy the one you want into your own stylesheet and edit it from there: they are plain CSS variables, not a setting you have to come back here to change.
Light and dark
Your page already knows whether it is light or dark. Wrap the tokens in the media query you use everywhere else, and the slot follows the same rule as the rest of your site, including when a visitor flips the preference mid-session.
[data-sb-slot] {
--sb-bg: #ffffff;
--sb-border: #e6e3de;
}The page behind it does not change here, only the tokens do. A dark card works on a light page and the other way round.
Tokens
Set them from your own stylesheet. The slot follows without you overriding a single class, and there is nothing to save anywhere.
[data-sb-slot] { --sb-radius: 14px; --sb-pad: 14px 16px; }The logo is the one most people reach for first. Here is the same slot at three sizes, so you can judge them against each other rather than one at a time.
[data-sb-slot] { --sb-logo: 44px; --sb-logo-radius: 10px; }| Token | Default | Effect |
|---|---|---|
| --sb-bg | transparent | slot background |
| --sb-color | inherit | text color |
| --sb-bg-image | none | gradient or image behind it |
| --sb-border | 18% of your text color | border color |
| --sb-border-w | 1px | border width |
| --sb-radius | 8px | corner radius |
| --sb-pad | 10px 12px | inner density |
| --sb-gap | 10px | space between logo and text |
| --sb-logo | 28px | logo size |
| --sb-logo-radius | 4px | logo corner radius |
| --sb-title-color | inherit | headline color |
| --sb-title-weight | 600 | headline weight |
| --sb-body-opacity | .75 | sentence opacity |
| --sb-body-size | .92em | sentence size |
| --sb-label-size | 10px | sponsored label size |
| --sb-label-opacity | .6 | sponsored label opacity |
| --sb-arrow-size | 16px | arrow size |
| --sb-arrow-opacity | .6 | arrow opacity |
| --sb-hover-color | your text color | hover effect color |
| --sb-carousel-width | 260px | width of a carousel card |
| --sb-carousel-gap | 16px | space between carousel cards |
A layout may change a default, never your value: the layout rules redeclare the same token with a different fallback, so anything you set explicitly still wins.
--sb-bg-image takes a gradient or an image, and stacks over --sb-bg. A gradient is a background image in CSS, not a color, which is why they are two tokens rather than one.
[data-sb-slot] {
--sb-bg: #12101c;
--sb-color: #ece9f5;
--sb-bg-image: linear-gradient(120deg, #6d3ff211, transparent 60%);
}
/* Une image de fond, en https et entre guillemets. */
[data-sb-slot] { --sb-bg-image: url("https://cdn.example.com/texture.png") }This is the one token allowed to use parentheses, so it is validated on its own terms: balanced parentheses, an allowlist of CSS functions, and any url() restricted to https in quotes. Everything else stays on the strict rule.
Your own CSS
The class names are stable, and our stylesheet sits at deliberately low specificity. You override it from yours without a single !important.
[data-sb-slot] .sbu {
border: none;
background: #fafafa;
font-family: "My Typeface", serif;
}
[data-sb-slot] .sbu-title { color: #b4530a; }
[data-sb-slot] .sbu-label { opacity: .45; }| Class | Element |
|---|---|
| .sbu | the link wrapping everything |
| .sbu--row, .sbu--stack… | the layout, on the same element |
| .sbu-logo | the sponsor's image |
| .sbu-text | the headline + sentence block |
| .sbu-title | the headline |
| .sbu-body | the sentence |
| .sbu-label | the sponsored label |
Your own markup
You already have a sponsor card that matches your site. Keep it as it is, mark the parts to fill, and we stop building anything.
<div data-sb-slot="footer">
<a data-sb="cta" class="my-card">
<img data-sb="logo" alt="" />
<span>
<strong data-sb="title"></strong>
<em data-sb="body"></em>
</span>
<small data-sb="sponsored"></small>
</a>
</div>| Attribute | What we put in it |
|---|---|
| data-sb="logo" | the src if it is an <img>, otherwise a background |
| data-sb="title" | the sponsor's headline |
| data-sb="body" | their sentence |
| data-sb="cta" | the link, if the element is an <a> |
| data-sb="sponsored" | the label, if you leave the element empty |
Every anchor is optional, the label included: it only decides where the label lands in your card. Leave it out and we place it ourselves, or keep the mention you already wrote.
If you do not already have a card you care about, take a layout instead.
What counts as an impression
You style the slot however you like, down to supplying your own markup. In exchange, an impression is only counted when it was genuinely seen. That is the whole deal, and the only thing we hold.
Squeeze the slot and watch the verdict change. The dimensions below are measured on the element you are looking at, against the same thresholds the script applies on your own page.
A slot shrunk to two pixels or hidden does not get you a warning and does not get you removed. It simply is not counted. We never argue with your CSS, we decline to count.
Thresholds
| Condition | Threshold |
|---|---|
| Visible surface | 50% of pixels |
| Continuous duration | 1 second |
| Rendered size | at least 120 × 24 px |
| Readable label | ≥ 9 px, contrast ≥ 3:1 |
Contrast is measured against the real background behind the label, with its opacity folded in, not against what the CSS claims.
A request stopped by an ad blocker costs you volume and never costs anyone integrity. The script reports that it failed to start, so a blocked page reads as blocked rather than as an audience that did not look.
Serve it from your own domain
Optional, and recommended. One rewrite rule and the slot becomes same-origin.
// next.config.js
export default {
async rewrites() {
return [{
source: "/dfu/:path*",
destination: "https://sponsorslot.dogfooded.com/dfu/:path*",
}];
},
skipTrailingSlashRedirect: true,
};// vercel.json
{
"rewrites": [
{
"source": "/dfu/:path*",
"destination": "https://sponsorslot.dogfooded.com/dfu/:path*"
}
]
}Then load the script from your own domain. The rewrite does nothing while the tag still points at ours:
<script src="/dfu/s.js" async></script>Latency is the small reason. The real one is that it makes your blocked-load figure trustworthy. Served from a third-party domain, the signal that says the script never started falls under the same filter rule as the script it was meant to report on, so a blocked page looks exactly like a page nobody looked at.
The trade-off: requests then reach us through your server, so visitors can no longer be told apart. Impressions and clicks stay exact, but reports show unique visitors as a lower bound, or n/a when all traffic went through the rewrite.
Everything works without it, with a less reliable blocked-load measurement and exact unique visitors.