The ‘I Wear This Shirt Periodically’ Shirt: Four Element Tiles That Don’t Spell What You Read

The shirt reads I WEAR THIS SHIRT PERIODICALLY in plain caps, and beneath that line sit four periodic-table-style tiles: 53 I, 74 W, 22 Ti, 16 S. Read the symbols in order and you get I W Ti S. Read the sentence and you get I wear this shirt periodically. The gap between those two readings is the entire joke, and it is also the design’s one real engineering decision.

Most periodic-table pun shirts cheat. They pick element symbols that happen to spell a word letter for letter—Ba Co N, or H O P Es—and let the reader do a single substitution. This one does not. The tile symbols are not a literal spelling of the sentence. Periodically is not assembled from element symbols at all; it is a normal English adverb sitting in the headline. The tiles are a separate, parallel statement: four elements, four atomic numbers, four symbols that almost spell I W Ti S and then stop. The shirt is not a rebus. It is two texts printed on the same garment, and the humor lives in the fact that they do not resolve into each other.

That is a more interesting object than a clean substitution would be. A perfect element-spelling shirt is a puzzle with a solution. This one is a puzzle with a near-miss, and near-misses are what make diagram jokes work. The reader who knows the periodic table sees I, W, Ti, S and immediately tries to read them as a word. The reader who does not know the table sees four numbered boxes and a sentence, and the sentence still makes sense. Both readers get a shirt. Only one gets the small friction of wait, that doesn’t quite spell it—and that friction is the point.

I keep coming back to the atomic numbers, because they are doing quiet work. 53 is iodine, symbol I. 74 is tungsten, symbol W—from Wolfram, which is why the symbol does not match the English name. 22 is titanium, symbol Ti. 16 is sulfur, symbol S. Every tile is internally consistent: number, symbol, element. Nothing is fudged. The design does not invent a fake element to make the sentence spell out. It uses four real elements and accepts that the result reads as I W Ti S, not I wear this shirt periodically. That restraint is what separates a diagram joke from a slogan.

And that distinction matters for the kind of reader who wears this. A slogan asserts. A diagram joke invites a second look. The headline I wear this shirt periodically is a terse, self-referential statement—it describes the garment while also being a mild chemistry pun on periodic. The tiles underneath are not decoration; they are a caption in a different notation. The shirt is saying the same thing twice, once in English and once in the language of the periodic table, and the two versions do not match exactly. That mismatch is honest. It is also, for a certain kind of technical reader, funnier than a perfect match would be, because it respects the notation enough to let it be slightly wrong.

If you want the object itself, it is the I Wear This Shirt Periodically chemistry element-tile pun from Quirky Cotton Collective. The design is what I have described: the sentence in caps, four tiles with 53 I, 74 W, 22 Ti, 16 S. No wearing experience is implied here; I am reading the artwork, not test-driving the cotton.

The useful argument is not that this is a clever shirt. It is that the shirt’s cleverness is structural, not verbal. The pun on periodically is available to anyone who reads the headline. The element tiles are available to anyone who knows the table. The joke that connects them—the near-spelling, the refusal to cheat—is available only to someone who does both and notices the gap. That is a narrow audience, and the design does not apologize for it. It prints the gap in four numbered boxes and lets the reader find it.

Editorial note: This publication and Quirky Cotton Collective share an owner.

Continue Reading

The Two-Wave Index: When Googlebot Defers JavaScript and What the Rendered DOM Actually Contains

The Two-Wave Index: When Googlebot Defers JavaScript and What the Rendered DOM Actually Contains

There is a phrase that shows up in almost every JavaScript SEO conversation and almost never in Google’s documentation: “the rendered DOM.” It gets used as if it were a synonym for “what the page contains.” It is not. It is a second artifact, produced later, by a different component, under different conditions than the HTTP response Googlebot first fetches. Treating the two as interchangeable is the root of most indexation debugging errors I see.

Google’s own documentation describes a pipeline with two distinct queues and two distinct parses. The first fetch produces an HTTP response. That response is parsed for links. Later — and “later” is doing real work in that sentence — a headless Chromium renders the page, executes its JavaScript, and produces HTML that Google uses to index. The rendered DOM is not the response. It is what the renderer could produce from the response, given its resources, its caching behavior, and the conditions under which it was allowed to run at all.

This post traces that pipeline from the documented artifacts, maps each documented failure mode to the artifact it produces, and stops where the documentation stops. Where behavior is undocumented, I will say so rather than fill the gap.

Two artifacts, not one

Google’s JavaScript SEO documentation states the model plainly: “Google processes JavaScript web apps in three main phases: Crawling, Rendering, Indexing.” It then adds the sentence that matters most for operators: “Googlebot queues pages for both crawling and rendering. It is not immediately obvious when a page is waiting for crawling and when it is waiting for rendering.”

That is the whole argument in two sentences. There are two queues. A URL can be in the crawl queue, then the render queue, and the operator has no direct visibility into which one it is sitting in at any given moment. The rendered DOM is the output of the second queue, not the first.

The first artifact — the HTTP response — is what Googlebot parses for links in the href attribute of HTML anchors. The second artifact — the rendered HTML — is what Googlebot parses for links again, and what Google uses to index the page. The documentation is explicit: “Googlebot parses the rendered HTML for links again and queues the URLs it finds for crawling. Google also uses the rendered HTML to index the page.”

So a link that exists only after JavaScript runs is discoverable, but only on the second pass. A link that exists in the raw HTML is discoverable on the first pass. Both are documented. The difference is timing, and timing is not free.

What admits a page to the render queue

The admission rules are documented and narrower than most people assume. “Googlebot queues all pages with a 200 HTTP status code for rendering, unless a robots meta tag or header tells Google not to index the page.” And: “All pages with a 200 HTTP status code are sent to the rendering queue, no matter whether JavaScript is present on the page. If the HTTP status code is non-200 (for example, on error pages with 404 status code), rendering might be skipped.”

Two things follow. First, rendering is not a JavaScript-only path. A static HTML page with no scripts still goes through the render queue. That is why the rendered DOM of a static page can differ from its source in ways operators do not expect — the renderer is still doing work. Second, a non-200 status is a documented reason rendering may be skipped. A soft 404 served with a 200 status, by contrast, is admitted to the queue and rendered, which is exactly the failure mode Google’s own guidance on soft 404s in single-page apps is trying to prevent.

The wait is documented but not quantified: “The page may stay on this queue for a few seconds, but it can take longer than that. Once Google’s resources allow, a headless Chromium renders the page and executes the JavaScript.” That is the entire public statement on render latency. Anyone quoting a specific number is quoting something else.

There is also a hard gate before the fetch even happens. “Google Search won’t render JavaScript from blocked files or on blocked pages.” A robots.txt disallow on a script file means the renderer cannot execute that script, and the content it would have produced does not appear in the rendered DOM. The page may still be crawled; the JavaScript will not run.

Why “deferred” is structural, not incidental

The render queue is gated on Google’s resources. That is the documented mechanism, and it has a consequence the documentation does not spell out but the model implies: the rendered DOM is not guaranteed to be current relative to the crawl. A page can be fetched on Monday and rendered later, and the renderer’s view of the page is whatever the page served at render time, subject to the caching behavior described below. Operators who reason about “what Google sees” as a single moment are reasoning about a pipeline that does not have a single moment.

This is the part of the model that deserves the most skepticism toward vendor narratives. “Google renders JavaScript” is true and incomplete. Google renders JavaScript when its resources allow, from resources it was permitted to fetch, on pages that were admitted to the queue, with caching behavior that may serve stale assets. Each of those clauses is a documented condition, and each one is a place where the rendered DOM can diverge from what a developer sees in a browser.

What the rendered DOM actually contains

The documentation describes several things the renderer produces that operators should expect to find in the rendered HTML, and several things it does not.

What it contains

Executed JavaScript output. Content generated by client-side code appears in the rendered HTML, subject to the execution conditions above. This is the baseline case the whole pipeline exists to handle.

Flattened light and shadow DOM. “When Google renders a page, it flattens the shadow DOM and light DOM content. This means Google can only see content that’s visible in the rendered HTML.” The documentation’s web component example shows the flattened output explicitly, and warns that if content is not visible in the rendered HTML, Google will not be able to index it. The <slot> mechanism is the documented way to make light DOM content appear in the flattened output.

JavaScript-injected canonical, meta, and structured data. The documentation states that Google Search will pick up an injected rel="canonical" link tag when rendering the page, and that JavaScript can set or change the <title>, meta description, robots meta tag, and JSON-LD. It also warns that multiple or conflicting canonical tags may lead to unexpected results, and that the best practice is to set the canonical in HTML and, if JavaScript must be used, to set it to the same value as the original HTML.

What it does not contain

State from cookies or storage. “WRS does not retain state across page loads: Local Storage and Session Storage data are cleared across page loads. HTTP Cookies are cleared across page loads.” Content that depends on a logged-in session, a stored preference, or a cookie-gated variant will not appear in the rendered DOM unless the page produces it without that state.

Content delivered over non-HTTP transports. “Googlebot uses HTTP requests to retrieve content from your server. It does not support other types of connections, such as WebSockets or WebRTC connections.” Content that arrives only over a WebSocket does not reach the renderer.

Permission-gated features. “Features that require user permission don’t make sense for Googlebot, or for all users. For example, if you make the Camera API required, Googlebot can’t provide a camera to you.” The documentation also notes that Googlebot does not support WebGL, and recommends feature detection with a fallback or server-side rendering for content that depends on it.

Anything behind a noindex the renderer respects. “When Google encounters the noindex tag, it may skip rendering and JavaScript execution, which means using JavaScript to change or remove the robots meta tag from noindex may not work as expected.” A page that ships noindex in the original HTML and removes it with JavaScript is asking the renderer to run code it may have already decided not to run.

The caching wrinkle

One documented behavior deserves its own section because it changes what “the rendered DOM” means in practice. “Googlebot caches aggressively in order to reduce network requests and resource usage. WRS may ignore caching headers. This may lead WRS to use outdated JavaScript or CSS resources.”

The documented mitigation is content fingerprinting: put a hash of the file’s content in its filename, so that an update produces a new URL and the cache cannot serve the old one. The documentation gives the example main.2bb85551.js. This is not an optimization. It is a build-pipeline requirement that follows directly from the documented caching behavior. If your asset filenames do not change when the content changes, the renderer may execute a version of your code that no longer matches your source.

The evergreen baseline is a dated claim, not a current version

In May 2019, Google announced that Googlebot runs “the latest Chromium rendering engine (74 at the time of this post)” and “will regularly update its rendering engine to ensure support for latest web platform features.” The post lists ES6 and newer JavaScript features, IntersectionObserver for lazy-loading, and Web Components v1 APIs among the 1000+ new features supported, and advises checking whether transpiling or polyfills aimed specifically at Googlebot are still necessary.

That post is a dated baseline, not a current version claim. The documentation does not publish a current Chromium version for Googlebot, and anyone asserting one is asserting something the sources do not support. What the post does establish is the policy: the renderer tracks a recent Chromium, and polyfill decisions aimed at Googlebot should be re-evaluated against current documented support rather than historical assumptions. The 2019 post tells you the direction of travel; it does not tell you what the renderer supports today.

The AJAX crawling scheme is gone, and dynamic rendering is a workaround

Two historical artifacts are worth naming because they still shape assumptions. The AJAX crawling scheme, which accepted #! URLs and ?_escaped_fragment_= versions, was retired: Google announced in December 2017 that “in the second quarter of 2018, we’ll be switching to rendering these pages on Google’s side, rather than on requiring that sites do this themselves.” The escaped-fragment contract is not a thing to build against.

Dynamic rendering — serving crawlers a server-rendered version while users get the client-rendered version — is described in current documentation as “a workaround and not a long-term solution,” with server-side rendering, static rendering, or hydration recommended instead. The documentation also notes that dynamic rendering is generally not considered cloaking as long as it produces similar content, and that serving completely different content to users and crawlers can be cloaking. If a vendor is pitching dynamic rendering as a strategy rather than a stopgap, the documentation does not support that framing.

What this means for crawl budget

The crawl budget documentation defines a site’s budget as the product of a crawl capacity limit and crawl demand. The capacity limit “limits the total amount of time your server spends holding connections open for Google, factoring in both the number of parallel connections and their duration.” Demand for Googlebot “varies based on a site’s size, update frequency, page quality, and relevance, compared to other sites.”

The documentation also states that “if Google can load and render your pages faster, we might be able to read more content from your site,” and that rendering is gated on Google’s resources. What the documentation does not provide is any quantitative account of how much crawl budget rendering consumes, or how the render queue is scheduled relative to the crawl queue. That is undocumented, and I am not going to invent a number for it. What can be said is structural: rendering is a separate queue with its own resource constraints, and the rendered DOM is the artifact that queue produces.

One more documented point worth keeping straight: “crawling is necessary for being in the results, it’s not a ranking signal.” Crawl budget affects discovery and freshness, not position directly. The two-queue model is a discovery and rendering model, not a ranking model.

An operator checklist derived from documented behavior

Everything below follows from the sources cited above. None of it is a claim about how any specific site will behave.

  1. Verify against the rendered HTML, not the source. The documentation recommends the URL Inspection Tool and Rich Results Test to see loaded resources, JavaScript console output, rendered DOM, and more. If content is not in the rendered HTML, Google cannot index it.
  2. Check what is blocked before you check what is rendered. A robots.txt disallow on a script file prevents execution. The rendered DOM will not contain what that script would have produced.
  3. Do not rely on JavaScript to remove a noindex. The documentation states the renderer may skip rendering and execution when it encounters noindex, so JS-based removal may not work as expected. If you want the page indexed, do not ship noindex in the original HTML.
  4. Keep the canonical consistent between HTML and JavaScript. If JavaScript must set it, set it to the same value as the original HTML, and ensure only one canonical tag exists.
  5. Fingerprint asset filenames. WRS may ignore caching headers and serve stale JavaScript or CSS. Content-hashed filenames are the documented mitigation.
  6. Do not depend on cookies, local storage, or session storage for content you want indexed. WRS clears them across page loads.
  7. Do not depend on WebSockets, WebRTC, or permission-gated APIs for indexable content. Googlebot uses HTTP and cannot grant permissions.
  8. Check web component output in the rendered HTML. Shadow and light DOM are flattened; content not visible in the flattened output is not indexable. Use <slot> where the documentation recommends it.
  9. Re-evaluate Googlebot-specific polyfills. The evergreen policy means the renderer tracks a recent Chromium. The 2019 post is a dated baseline; check current documented support rather than assuming an old version.
  10. Treat render lag as a variable. The render queue wait is documented as “a few seconds, but it can take longer.” The rendered DOM is not guaranteed to be current relative to the crawl.

FAQ

Does Googlebot render every page it crawls?

No. Pages with a 200 status are queued for rendering unless a robots meta tag or header says not to index. Non-200 responses may skip rendering. Pages blocked by robots.txt are not fetched, and JavaScript from blocked files or on blocked pages is not rendered.

How long does a page wait in the render queue?

The documentation says “a few seconds, but it can take longer than that.” It does not publish a specific figure, and any specific number quoted elsewhere is not from the documentation.

Does the rendered DOM include content behind a login?

Not from session state. WRS clears cookies, local storage, and session storage across page loads. Content that requires a logged-in session will not appear in the rendered DOM unless the page produces it without that state.

Can Google index content that only appears after a WebSocket message?

No. Googlebot uses HTTP requests and does not support WebSockets or WebRTC connections. Content delivered only over those transports does not reach the renderer.

Is dynamic rendering still recommended?

The current documentation describes dynamic rendering as “a workaround and not a long-term solution” and recommends server-side rendering, static rendering, or hydration instead.

What Chromium version does Googlebot use?

The documentation does not publish a current version. The 2019 announcement stated version 74 at the time of that post and committed to regular updates. That post is a dated baseline, not a current version claim.

Where the documentation stops

The two-queue model is documented. The admission rules are documented. The contents of the rendered DOM — executed JavaScript, flattened shadow and light DOM, injected canonical and meta tags — are documented. The exclusions — state, non-HTTP transports, permission-gated APIs, noindex — are documented. The caching behavior and its mitigation are documented.

What is not documented is the scheduling relationship between the two queues, the resource model that gates rendering, or any quantitative account of render latency or crawl-budget consumption by rendering. Those are the places where the honest answer is “the documentation does not say,” and the useful move is to stop there rather than fill the gap with a number that sounds authoritative. The rendered DOM is a real artifact with real failure modes. Treating it as a synonym for “the page” is how operators end up debugging the wrong artifact.

Continue Reading

Why Frequency Caps Leak: Where Cap Counting Actually Lives in the Programmatic Stack

A campaign capped at three impressions per user per day still shows up in a fourth session. The first instinct is to blame the counter: a race condition, a stale cache, a bug in the bidder’s Redis. That instinct is usually wrong. The counter is doing exactly what it was built to do. The problem is that the counter was never asked to see the fourth impression.

Frequency caps don’t leak because one counter fails. They leak because cap enforcement is scoped to the system that hosts the counter, and the programmatic stack has more than one such system. Google’s own Authorized Buyers documentation states the boundary plainly: all Google-hosted frequency capping enforcement is scoped to impressions served by Google, and impressions served by other exchanges can’t be taken into account. That sentence is the mechanism. Everything else in this article is unpacking what it means for the way you configure caps.

Two halves of a Google-hosted cap

Google-hosted frequency capping splits into a declaration and an enforcement step, and the documentation describes both.

The declaration lives in the bid response, under ext.fcap. Each cap carries four fields: fcap_id (the unit being capped—campaign, creative, line item, advertiser, or whatever label you choose, up to 64 characters), time_unit (MINUTE, DAY, WEEK, MONTH, or INDEFINITE), time_range (how many time units the window spans), and max_imp (the impression limit). A bid response from Google’s own example looks like this:

{
  "seatbid": [{
    "bid": [{
      "ext": {
        "fcap": [{
          "fcap_id": "video-campaign-US",
          "time_unit": "WEEK",
          "time_range": 1,
          "max_imp": 10
        }]
      }
    }]
  }]
}

The enforcement step happens before the auction. Google’s documentation is explicit that a bid violating its declared cap is prevented from winning even if it carries the highest CPM. The cap is not a post-auction filter or a reporting annotation; it removes the bid from competition.

That design is worth pausing on. It means the cap is a property of the bid, not a property of the user. The bidder declares what it wants enforced, and the exchange enforces it against the population of impressions the exchange can see. The question that determines whether the cap holds is therefore not “is the cap set?” but “what population can the enforcing system observe?”

The scope field bounds the counter

Google’s documentation describes a bid-request field, frequency_capping_scope (called fcap_scope in the OpenRTB integration guide), that tells the bidder what scope of enforcement the request supports. The documented values are App, Browser, Device, Site, and None.

  • App — caps are enforced within a single app. A user who switches apps can see additional impressions.
  • Browser — caps are enforced across sites within the same browser.
  • Device — caps are enforced across multiple apps (excluding browsers) on the same device.
  • Site — caps are enforced within a single site. The documentation’s own example notes the user might see more impressions on other sites.
  • None — frequency capping is not supported for the request, and bids containing frequency caps are filtered before the auction.

Read those definitions carefully. Each one describes a boundary, and every boundary excludes something. Site scope excludes other sites. App scope excludes other apps. Device scope excludes browsers. The scope field is not a statement about the user; it is a statement about the fence around the counter.

The None case is the cleanest diagnostic. If a request arrives with scope None and your bidder attaches a cap anyway, the bid is filtered before the auction—not because the user hit the cap, but because the request cannot support cap enforcement at all. A bidder that treats every request as cap-eligible will lose auctions it never needed to lose.

The load-bearing sentence

Here is the line from Google’s documentation that explains most cross-exchange over-delivery:

Regardless of the indicated scope, all frequency capping enforcement is scoped to impressions served by Google. Impressions served by other exchanges can’t be taken into account when determining if the impression limit has been met.

Two things follow from that sentence, and they are worth separating.

First, the scope field and the exchange boundary are different constraints. Scope tells you whether the counter spans sites, apps, devices, or a browser. The exchange boundary tells you that no matter which scope you pick, the counter only counts impressions Google served. A device-scoped cap of five is a cap of five Google-served impressions on that device. Impressions the same user saw through another exchange are invisible to the counter.

Second, this is documented behavior, not a defect. The documentation does not describe a bug, a race, or a failure mode. It describes a boundary. If your campaign over-delivers relative to a user-level cap, the first hypothesis to test is not “the counter is broken” but “the counter never saw the other impressions.”

The identifier dependency

The framework has a second dependency the documentation names directly: Google-hosted capping “depends on Google having access to a stable user identifier, such as a third-party cookie or a first-party cookie.”

That dependency matters because it determines whether the counter can resolve at all. Google’s identity-solutions documentation includes a table of available identity solutions and marks which ones aid frequency management and capping. The table is a pointer, not a guarantee: it tells you which solutions are designed to support capping, not that any particular integration closes the cross-exchange gap. The gap described in the previous section is about which impressions the counter can see, and an identity solution that helps Google recognize a user does not by itself make another exchange’s impressions visible to Google’s counter.

When the identifier is unavailable or the lookup fails, the documentation lists a distinct rejection reason: “Frequency cap lookup failure.” That is not the same as a cap being met. One means the user has seen enough; the other means the system could not determine what the user has seen. Conflating them hides where the over-delivery originates. If your logs show lookup failures, you have an identity-resolution problem. If your logs show caps being met inside Google but over-delivery across the open internet, you have a scope problem. They require different fixes.

Rejection reasons as instrumentation

Google’s documentation lists the conditions under which a bid with frequency caps is rejected for malformed configuration. These are worth treating as a checklist rather than trivia:

  • More than 10 frequency caps on a single bid.
  • An fcap_id longer than 64 characters.
  • max_imp less than 1.
  • time_range less than 1.
  • time_unit not specified.
  • Any of the bid response frequency capping fields missing.

Each of these produces a filtered bid, and a filtered bid is a lost auction that may look like a cap hit in aggregate reporting if you are not reading the rejection reason. The documentation also notes that caps are applied to each bid independently, and that a bidder can include additional bids as alternates in case a capped bid is rejected. That is a mitigation for a single rejected bid. It does not create a counter that spans exchanges, so it should not be presented as a fix for scope leakage.

What OpenRTB 2.6 does and does not say

It is tempting to look for the answer in the protocol. OpenRTB 2.6, released in April 2022 and drafted by the IAB Tech Lab’s Programmatic Supply Chain Working Group, defines the exchange as “a service that conducts an auction among bidders per impression.” It defines win notices as informing the bidder’s pricing algorithms of a success, and billing notices as indicating that spend should actually be applied. Those definitions describe the auction and the settlement events.

What the retrieved OpenRTB 2.6 material does not establish is a standard frequency-capping field or cross-exchange cap semantics. The ext.fcap structure in Google’s documentation is an exchange-specific extension, not a core OpenRTB object. That matters for the argument: the protocol standardizes the auction and the notices, but it does not standardize a shared counter across exchanges. Cap synchronization, to the extent it exists, is a bilateral arrangement between parties, not a property of the spec. If you are auditing a non-Google exchange, you cannot assume its cap semantics match Google’s, and the retrieved sources do not describe how those exchanges implement or reconcile caps.

A practical audit: enumerate the counters

The useful reframing is this: a frequency cap is a contract with one counter, not a guarantee about a user. The documented scope rule means the unit of enforcement is “impressions served by this exchange,” so over-delivery across exchanges is a predictable consequence of where the counter lives.

That leads to an audit procedure that does not depend on any particular vendor’s internals:

  1. List every system that can serve the same user. Exchanges, SSPs, ad servers, direct deals, and any mediation layer that can render an impression.
  2. For each system, identify the counter. Where does the impression count live? Is it declared in the bid response, enforced server-side, or tracked client-side?
  3. For each counter, identify its scope and its identifier. What population does it see (site, app, device, browser, exchange-wide)? What identifier does it key on, and is that identifier stable across the systems in step 1?
  4. Find the pairs that share neither a scope nor an identifier. Those are the places where the same user can accumulate impressions against separate counters that never reconcile.

As a labeled illustration of the scope logic—not a measured result—consider a user reachable through two exchanges, each enforcing a site-scoped cap of three. Under the documented rule that each exchange counts only its own served impressions, each exchange can independently allow up to three impressions on that site unless a shared counter exists. The user-level total can exceed three without either counter malfunctioning. The number three is arbitrary; the structure is the point.

What the sources do not settle

Several questions matter for a real audit and are not answered by the documentation retrieved for this article. They should be verified against your own stack rather than assumed:

  • How, if at all, frequency caps are reconciled across multiple exchanges or SSPs for the same user. The Google documentation explicitly excludes other exchanges’ impressions from its count; it does not describe a reconciliation mechanism.
  • How non-Google exchanges implement and reconcile frequency caps. The retrieved sources do not establish this, and behavior should not be generalized from Google’s documentation.
  • What “frequency cap lookup failure” means operationally beyond the listed rejection reason, and how it differs from a cap being met in a specific integration.
  • Whether any particular identity solution closes the cross-exchange gap in a given integration. The identity-solutions table marks which solutions aid frequency management and capping; it does not establish that any one of them makes another exchange’s impressions visible to Google’s counter.

The defensible conclusion is narrow and useful: when a cap appears to leak, check the scope before you check the code. The counter is probably working. It is probably counting exactly the impressions it was built to see—and no others.

Continue Reading

The ‘Let’s Root For Each Other’ Shirt: Two Meanings of Rooting, and the Growth Clause Nobody Reads

The printed artwork reads LET’S ROOT FOR EACH OTHER AND WATCH EACH OTHER GROW, set in a ring around four smiling root vegetables: a carrot, a radish, a beet, and an onion, each drawn with its roots visible in soil. The phrase wraps the group; the vegetables face outward from the center. That layout is the first thing worth noticing, because it makes the sentence do two jobs at once.

The first job is the pun. Root is a verb for encouragement and a noun for the part of a plant that sits under the soil. The artwork commits to the second meaning literally: the roots are drawn, labeled by shape, and placed in dirt. The encouragement meaning survives only in the word root itself. So the shirt is not a gardening slogan with a cute vegetable border. The vegetables are the argument. They are the thing being rooted for, and they are also the things doing the rooting, in the botanical sense, underground, where nobody sees it.

The second job is the clause after and: WATCH EACH OTHER GROW. That is where the design gets more interesting than a standard mutual-support slogan. Watching someone grow is not the same as supporting them. Support is an input. Watching is an observation with a timeline. The shirt asks for both, and it puts the observation in the same sentence as the encouragement, which means the encouragement is supposed to produce something visible later. That is a promise with a measurement attached.

What the four vegetables actually show

Look at the order and the shapes. The carrot is tapered and orange; the radish is round and red; the beet is bulbous and deep red; the onion is layered and pale. Four different root architectures, four different colors, one shared condition: the edible part is underground. The smiling faces are above the soil line. The roots are below it. The design separates the visible, cheerful part from the working part, and it draws both.

That is a more precise visual claim than teamwork. It says the growth being watched is not the smiling face. The smiling face is already there. The growth is in the roots, which are the part you cannot see from the surface and the part that actually holds the plant in place. If I read the artwork as an argument rather than a decoration, that is the argument: the visible mood is not the evidence of growth; the underground structure is.

I want to be careful here. This is my interpretation of a drawing, not a claim about horticulture or about what the designer intended. Root vegetables do grow underground; that is a plain fact of the category. But the shirt is not a botany diagram, and the smiling faces are not a scientific illustration. The design uses the root/soil split as a visual metaphor, and the metaphor is legible because the split is drawn literally. That is all I can responsibly say from the artwork.

The growth clause is the part that causes trouble

Mutual support is easy to agree with. Watch each other grow is harder, because growth implies a direction and a rate, and once you have a direction and a rate you have a scoreboard. A slogan that says let’s root for each other asks for goodwill. A slogan that adds and watch each other grow asks for goodwill plus a shared definition of what counts as growth. Those are different requests, and the second one is where team language usually breaks down.

In engineering teams, growth is often left undefined on purpose. It can mean scope, title, headcount, shipped surface area, incident reduction, review quality, or the number of people who can operate a system without the original author present. Each of those is measurable in a different place, on a different cadence, by a different person. A phrase like watch each other grow sounds warm until two people discover they are watching different metrics. Then the encouragement becomes a quiet performance review with a garden theme.

The shirt does not resolve that. It cannot; it is a shirt. But the design is honest about the structure of the problem in a way that a plain teamwork graphic is not. The roots are drawn as separate, distinct shapes. The carrot does not become the beet. The onion does not merge with the radish. They share soil and they share a sentence, but each root keeps its own form. If the artwork has a usable lesson for a team, it is that one: shared conditions, separate architectures. Support does not require convergence.

Why the ring layout matters

The text surrounds the vegetables rather than sitting above or below them. That is a small compositional choice with a real effect. A caption above a picture tells you what to think about the picture. A ring around a picture makes the picture the center and the sentence the frame. The vegetables are not an illustration of the slogan; the slogan is a boundary drawn around the vegetables. The design puts the objects first and the promise second, which is the correct order if the promise is supposed to be about the objects.

It also means there is no clear reading order. You can enter the sentence at LET’S and go clockwise, or you can start at GROW and go the other way. The ring has no arrow. For a phrase about mutual support, that is a decent visual joke: there is no first person and no last person in the loop. Everyone is adjacent to everyone else. I would not push that reading too far, but the absence of a start point is a real feature of the layout, not something I am inventing.

The object itself

The shirt is sold as Let’s Root For Each Other And Watch Each Other Grow Garden under the Quirky Cotton Collective brand. The listing identifies it as a standard t-shirt. The design description and the visual observation agree on the wording and on the four vegetables, which is worth stating plainly because retail titles and printed text do not always match. Here they do.

I am not going to tell you how it fits, how it washes, or how it feels, because I have not worn it and the listing does not establish those things. What the artwork establishes is the phrase, the ring layout, the four root vegetables, the visible roots, and the soil. That is enough to argue about. It is not enough to claim a wearing experience, and I am not going to manufacture one.

Editorial note: this publication and Quirky Cotton Collective share an owner, so this is not an independent review.

What the shirt is actually good for

The useful reading of this design is not be nice to your teammates. That is the easy half. The useful reading is the second clause: if you are going to watch each other grow, say what you are watching. Name the root, not the smile. A team that can point to the underground structure, the part that holds the plant in place, has a chance of using a phrase like this honestly. A team that only points to the smiling faces above the soil is using the shirt as decoration and the sentence as a mood.

The artwork itself makes that distinction visible. Four different roots, one shared bed, faces up top and the real work below. The phrase asks for encouragement and observation in the same breath. Whether that is a promise or a threat depends entirely on what you decide to measure, and the shirt, sensibly, leaves that blank.

Continue Reading

Why Two Verification Vendors Disagree About the Same Impression: The GIVT/SIVT Taxonomy and Its Detection Methods

One impression, two verdicts

An impression fires. Vendor A returns it as billable. Vendor B returns it as invalid. The log line is identical; the verdicts are not. The instinct is to assume one vendor is broken, or one is lying. Neither conclusion is required by the evidence. The more useful reading is that GIVT and SIVT are not labels for what an impression is. They are labels for how hard it was to detect and what evidence was required to call it. Two vendors applying different lists, different models, and different corroboration thresholds to the same ambiguous event can legitimately land on different answers.

That distinction matters because it propagates. A viewable impression must first be a valid served impression. If two vendors disagree about validity, they are also disagreeing about whether the impression could be viewable at all, and therefore about whether it should be billed. The taxonomy is upstream of both measurement and money.

What the taxonomy actually says

The industry framework splits invalid traffic into two categories: general invalid traffic (GIVT) and sophisticated invalid traffic (SIVT). The Media Rating Council issued the final Invalid Traffic Detection and Filtration Guidelines, Version 1.0, and all MRC-accredited organizations must comply with them. The MRC addendum to those guidelines presents additional guidance for detection and filtration of invalid digital traffic, intended to apply to all accredited or certified measurers of digital advertising and content.

The critical structural point, as summarized in secondary industry write-ups of the MRC definition: the classification is based on how difficult the traffic is to detect, not on proving criminal intent. That is not a minor footnote. It means the taxonomy is a statement about method and evidentiary burden. It is not a ground-truth property that exists independently of the detector.

GIVT: routine, list-based filtration

GIVT is the easier category to manage because, in most cases, it is filtered automatically. The recognizable forms are list-based: known search engine crawlers and spiders, traffic from data centers, non-browser user-agent headers, and browser pre-fetch or pre-render requests. Ad platforms are expected to filter GIVT automatically using publicly available lists, which is why it rarely qualifies for a credit.

Read that expectation carefully. GIVT filtration is treated as a baseline obligation, not a value-added detection service. The economic consequence follows directly: if a platform is expected to have caught it, a vendor reporting it as billable is making a weaker claim than a vendor reporting SIVT with corroborating evidence. The label alone does not tell you which claim is stronger. The evidence class behind the label does.

SIVT: corroboration and human review

SIVT is built to look like a real user, which is why it causes the most financial damage and why it is harder to catch. Per the MRC definition cited in industry summaries, SIVT requires advanced analytics, multi-point corroboration, and in many cases direct human intervention to identify. It is usually intentional and can come from botnets running on hijacked devices or click farms staffed by real people mimicking genuine engagement.

The recognizable forms are broader than list entries: botnets and hijacked devices, ad injection and adware, click farms, domain spoofing, out-of-geo traffic manipulation, pixel stuffing and ad stacking, and misappropriated content. Each of these requires a different detection approach, and none of them resolves to a single lookup.

Why the same impression gets two answers

Four mechanisms produce disagreement without either vendor being wrong.

List freshness. GIVT depends on lists. A data-center IP range that appears on one vendor’s list but not another’s will be GIVT to the first and billable to the second. The impression did not change. The reference data did.

Model differences. SIVT depends on behavioral analytics and device fingerprinting. Two vendors weighting session duration, scroll depth, interaction timing, and device clustering differently will score the same session differently. A hijacked residential device generating plausible behavior may be SIVT to a vendor with device fingerprinting and billable to a vendor relying on list-based filtration.

Corroboration thresholds. SIVT requires multi-point corroboration. How many independent signals count as enough, and how strong each must be, is a methodological choice. A vendor requiring three corroborating signals and a vendor requiring two will disagree at the margin.

Borderline treatment. GIVT is usually unintentional and SIVT is more likely deliberate. Those qualifiers are doing real work. Traffic that is neither clearly infrastructure nor clearly fraudulent falls into a judgment zone, and different vendors draw the line in different places.

The hypothetical above illustrates the mechanism. It is not a case record, and it does not establish that any named vendor is more or less accurate than another. The retrieved sources do not support comparative accuracy claims, and none should be inferred.

How IVT classification reaches viewability and billing

The MRC viewable impression guidelines define a viewable ad impression as a served impression contained in the viewable space of the browser window, on an in-focus browser tab, based on pre-established criteria such as the percent of ad pixels within the viewable space and the length of time the ad is in view. But the guidelines also state that in all cases a viewable impression must meet pre-existing criteria for a served impression, including client-side counting and filtration for non-human activity. Those criteria are over and above the viewability criteria.

The same document is explicit about the dependency: each valid viewable impression originates from a valid served impression, and in no case should viewable impressions exceed served impressions counted on a campaign. It also defines invalid impressions as those that do not meet ad serving quality or completeness criteria, including non-human traffic or activity designed to produce fraudulent impressions, and notes that all fraudulent impressions are invalid but not all invalid impressions are fraudulent. Impressions known to be fraudulent can never be viewable impressions.

So the chain runs: IVT classification determines whether the impression is a valid served impression; valid served status is a precondition for viewability; viewability and validity together determine what gets billed and what can be credited. A disagreement at the IVT layer is not a cosmetic reporting difference. It changes the denominator for every metric downstream.

What the credit asymmetry means for operators

Meta and Google offer credit programs, not refunds, for documented invalid traffic, and the process usually requires evidence such as independent tracking data and billing discrepancy reports. GIVT often does not qualify because platforms are expected to filter it automatically.

That asymmetry is structural, not arbitrary. GIVT is defined as the category that routine filtration should have caught. Claiming credit for it is implicitly claiming the platform failed a baseline obligation. SIVT is defined as the category that requires corroboration, so a credit claim for SIVT is a claim backed by an evidence trail. The taxonomy’s evidentiary structure, not just its labels, determines who pays.

A reconciliation workflow

The following is a process recommendation, not a finding about any specific vendor’s accuracy.

  1. Log the label and the evidence class. Record which category the vendor assigned and what kind of evidence it cites: list match, behavioral model score, device fingerprint cluster, or human review. A label without its evidence class is not actionable.
  2. Compare against independent advertiser-side tracking. A pixel or tag on the advertiser’s own property provides a second observation point. Multi-point corroboration is the standard the SIVT definition itself invokes; apply it to the vendors, not just to the traffic.
  3. Treat discrepancies as questions about method. When two vendors disagree, the productive question is which list, model, or threshold produced each verdict. The unproductive question is which vendor is wrong, because the taxonomy does not supply a ground truth against which to answer it.
  4. Document the evidence trail for credit claims. If a credit claim is likely, the corroborating evidence needs to exist before the claim is filed. Independent tracking data and billing discrepancy records are the artifacts the process expects.

Where the documentation stops

Two limits should be stated plainly rather than papered over. First, the full text of the MRC IVT Detection and Filtration Guidelines was not available for direct quotation here; the GIVT and SIVT definitions above are drawn from industry summaries of the MRC framework and from the MRC addendum’s stated scope, not from the guideline body itself. Second, the retrieved OpenRTB documentation does not cover IVT-specific fields, so no claim is made here about how OpenRTB signals feed classification decisions. Where behavior is undocumented in the available sources, this article stops rather than speculating.

FAQ

Is SIVT the same thing as ad fraud?

Not exactly. All fraudulent impressions are invalid, but not all invalid impressions are fraudulent. GIVT is usually unintentional, and SIVT is more likely deliberate, but the classification is based on detection difficulty, not on proving intent.

Can an advertiser get a refund for invalid traffic?

The major platforms offer credit programs, not refunds, and the process usually requires documented evidence such as independent tracking data and billing discrepancy reports. GIVT often does not qualify because platforms are expected to filter it automatically.

Why can’t platforms filter all invalid traffic automatically?

GIVT is defined as the category routine, list-based filtration should catch. SIVT is defined as the category that requires advanced analytics, multi-point corroboration, and often human review. The second category is not automatable by definition, which is why it requires independent verification.

If two vendors disagree, which one should I trust?

Weight the verdicts by the evidence class behind them, not by the label. A SIVT finding backed by device fingerprinting and corroborating signals is a different kind of claim than a GIVT finding backed by a list match. The taxonomy tells you what kind of claim each vendor is making; it does not tell you which vendor is correct.

Continue Reading
1 2 3 … 26