Transaction IDs Without Collateral Damage: Seller Tactics To Deduplicate Auctions While Preserving Yield

How sellers can use OpenRTB transaction IDs to enable buyer-side deduplication while protecting competition, coverage, and yield across web, app, and CTV.

Transaction IDs Without Collateral Damage: Seller Tactics To Deduplicate Auctions While Preserving Yield

Transaction IDs Without Collateral Damage: Seller Tactics To Deduplicate Auctions While Preserving Yield

Executive overview

Transaction IDs are now a fact of life in programmatic. Buyers use them to deduplicate multiple bid requests that describe the same ad opportunity across supply paths. That is good for efficiency. Implemented poorly, it can also dampen auction pressure, reduce coverage, and leak yield from honest sellers. This article offers a pragmatic seller playbook for source.tid implementation that enables buyer-side deduplication without collateral damage. We will break down what tid is supposed to do, the common pitfalls that erode revenue, and concrete, channel-specific tactics for web, app, and CTV. We will also show sample payloads, guardrails, and monitoring techniques. The perspective here is firmly supply side. The guidance aligns with privacy by design and the transparency stack sellers.json, ads.txt, and schain. Along the way, we note where Red Volcano’s publisher and CTV intelligence can help you validate deployment, spot duplication hot spots, and keep your supply chain honest.

What transaction IDs are and why buyers care

OpenRTB defines a Source object that travels with each bid request. Within it, the tid field is the transaction identifier that should be common across all requests that represent the same ad opportunity across exchanges and intermediaries. Buyers and DSPs rely on tid to avoid bidding multiple times on the same impression, a behavior that wastes QPS, introduces pacing risk, and distorts attribution. Several public references describe the intended use:

  • OpenRTB Source.tid: The Source object’s tid is a transaction ID common across all bid requests for the same auction opportunity, enabling deduplication across supply paths [BidSwitch docs, “Source Object”] and vendor implementations of OpenRTB 2.5 and 2.6 reference.
  • Vendor references: OpenRTB 2.5 references and partner specs document tid as the cross-request transaction identifier used in dedup workflows Smaato OpenRTB 2.5.
  • Prebid Server: Community docs describe population of id, imp.id, source.tid, and imp.ext.tid in server-side auctions, making it a practical mechanism for publishers running mixed client and server header bidding Prebid Server features.
  • Transparency context: The IAB Tech Lab’s transparency stack sellers.json and SupplyChain object help buyers trace paths while tid helps deduplicate the same opportunity across those paths Google Ad Manager on SupplyChain object and IAB Tech Lab FAQ.

In short, buyers want fewer redundant auctions for the same impression. Sellers want every legitimate opportunity to be fairly represented and competitively priced. The implementation details are where these goals can collide.

The collateral damage problem

When tid is incorrect or oversimplified, harmless deduplication becomes harmful suppression. That suppression takes several forms:

  • False positive deduplication: Distinct opportunities are collapsed by buyers. For example, two different ad slots on the same pageview share a tid. A buyer bids once, supply competition falls, and CPMs underperform.
  • Cross-refresh suppression: Refreshes that should be monetized as independent opportunities get the same tid. Buyers throttle or discard subsequent requests because they look like duplicates.
  • Channel path bias: Header bidding client, server, and mediation frameworks assign different tids for the same opportunity or the same tid for different opportunities. Buyers adopt an internal heuristic that unintentionally favors one path, skewing win rates and clearing prices.
  • CTV pod miscollapsing: SSAI vendors or distributors reuse a tid across an entire pod or session. DSPs deduplicate at the pod level. Slots later in the pod starve, causing underdelivery and makegoods.
  • Resale ambiguity: Resellers do not preserve upstream tid or compute their own incorrectly. Buyers cannot reconcile supply paths. SOP heuristics kick in and cut paths that look redundant.

The result is real money left on the table. The frustrating part is that most of this is avoidable with better scoping, entropy, and hygiene around tid generation and propagation.

Design principles for tid that deduplicates correctly

The first order design question is scope. What exactly should a single tid represent, and how long should it live? Here is a set of principles we recommend for sellers, wrappers, and intermediaries:

  • Scope to the atomic ad opportunity: A tid should map to exactly one attempt to sell one ad slot instance. Not a pageview, not a pod, not a session. One slot, one refresh cycle, one pod position equals one tid.
  • Preserve across parallel supply paths: If the same slot instance is sold through multiple SSPs in parallel, those parallel bid requests should carry the same tid. That is the dedup value for buyers.
  • Never reuse across distinct impressions: New slot instance equals new tid. New refresh equals new tid. New pod position equals new tid. Different screens or placements on the same pageview equals different tids.
  • Generate high entropy, collision resistant IDs: Use UUIDv4 or cryptographic random 128-bit values. Avoid short hashes, timestamps alone, or predictable sequences.
  • Short TTL and privacy minimization: A tid should expire quickly. Do not log or attach user identifiers. Treat the tid as a non-linkable handle to an ad opportunity, not a user session.
  • Propagate via Source.tid, mirror in ext if needed: Use source.tid. If adapters require imp.ext.tid for historical reasons, mirror the value, but keep a single source of truth.
  • Preserve upstream tid in reselling: If you are an intermediary reselling, you should preserve the upstream tid in source.tid and use schain to express the hop. Do not mint a new tid unless you truly create a new ad opportunity.

These principles sound simple. In practice, you need per-channel playbooks and tooling to execute them consistently.

Web: header bidding, ad server, and refresh

Client and server header bidding

Most modern publisher stacks mix client Prebid.js, Prebid Server, and direct SDK adapters. The goal is to create one tid for a given slot instance and make sure every SSP path that represents that same instance reuses it. Recommended approach:

  • Generate at the wrapper level: The wrapper, not a single adapter, should mint the tid for each ad unit request cycle and assign it to every participating bidder.
  • Propagate via Prebid Server: When you use server-side bidders, ensure Prebid Server is configured to populate source.tid consistently and not override per-slot tids unless empty. The Prebid Server feature pages describe how it fills id, imp.id, source.tid, and imp.ext.tid docs.
  • Coordinate with GAM: If you send parallel Open Bidding or line item calls, keep tid unchanged across the parallel SSP connections but mint a new tid when the ad server triggers a refresh or a new slot becomes viewable.

Sample pseudocode for tid generation in a wrapper:

// Wrapper-level transaction ID service
const TID = (() => {
// Map key: adUnitCode + requestCycleId
const tids = new Map();
function uuidv4() {
// Secure random UUID v4
const buf = new Uint8Array(16);
crypto.getRandomValues(buf);
buf[6] = (buf[6] & 0x0f) | 0x40;
buf[8] = (buf[8] & 0x3f) | 0x80;
const hex = [...buf].map(b => b.toString(16).padStart(2, '0'));
return [
hex.slice(0, 4).join(''),
hex.slice(4, 6).join(''),
hex.slice(6, 8).join(''),
hex.slice(8, 10).join(''),
hex.slice(10, 16).join('')
].join('-');
}
function getTid(adUnitCode, requestCycleId) {
const key = `${adUnitCode}:${requestCycleId}`;
if (!tids.has(key)) tids.set(key, uuidv4());
return tids.get(key);
}
function nextRequestCycleId() {
// Incrementing per-pageview cycle counter for refreshes or lazy loads
// Reset when pageview changes
window.__rvReqCycle = (window.__rvReqCycle || 0) + 1;
return String(window.__rvReqCycle);
}
return { getTid, nextRequestCycleId };
})();
// Usage per ad unit request
const cycleId = TID.nextRequestCycleId();
adUnits.forEach(unit => {
const tid = TID.getTid(unit.code, cycleId);
unit.bids.forEach(bid => bid.ext = { ...(bid.ext || {}), tid });
});

OpenRTB request snippet for a given slot during that cycle:

{
"id": "breq-789",
"source": {
"tid": "f7ad5d86-8f2e-4c70-9d1b-8e1db6b4f3c2",
"ext": {
"schain": {
"ver": "1.0",
"complete": 1,
"nodes": [
{"asi": "publisher.com", "sid": "1234", "hp": 1, "rid": "slot-001"},
{"asi": "ssp-a.com", "sid": "pub-789", "hp": 1}
]
}
}
},
"imp": [
{
"id": "imp-001",
"tagid": "slot-001",
"banner": {"w": 300, "h": 250},
"ext": {
"tid": "f7ad5d86-8f2e-4c70-9d1b-8e1db6b4f3c2"
}
}
],
"site": {"domain": "publisher.com", "page": "https://publisher.com/article"},
"tmax": 700
}

Key behavior:

  • Same slot within the same cycle equals same tid across bidders.
  • Different slots, even in the same cycle, get different tids.
  • New cycle on refresh or lazy load creates new tids for all slots.

Lazy load, refresh, and viewability

Refresh and lazy loading can silently break correct scoping. Many wrappers treat “request cycle” loosely, which leads to accidental tid reuse. Guardrails:

  • Bind tid to a concrete trigger: Use a viewability threshold or explicit refresh event as the moment you mint a tid for that slot. Do not mint at page load for slots that are not yet viewable.
  • Expire tids on slot teardown: When the slot is destroyed or collapsed, purge its tid from memory.
  • Respect ad server pacing: If GAM or your ad server delays a refresh, do not reuse old tids to shortcut the process. It will look like duplication to buyers.

Recommended monitoring

You cannot fix what you cannot see. Monitor for duplication hygiene with your log pipeline. Example SQL-like analysis to catch false positives:

-- Distinct impressions sharing a tid within a short window
SELECT
source_tid,
COUNT(DISTINCT CONCAT(site_domain,'|', imp_tagid, '|', request_cycle)) AS distinct_opportunities,
MIN(ts) AS first_seen,
MAX(ts) AS last_seen
FROM rtb_requests
WHERE ts >= NOW() - INTERVAL '1 day'
GROUP BY source_tid
HAVING COUNT(*) > 5
AND COUNT(DISTINCT CONCAT(site_domain,'|', imp_tagid, '|', request_cycle)) > 1
ORDER BY distinct_opportunities DESC
LIMIT 100;

Operational goal:

  • High reuse only when the opportunity is truly the same across SSPs.
  • Low or zero reuse across different slots or cylinders.

Red Volcano note: Our Magma Web and technology stack tracking can help audit wrapper behaviors and surface where different SSPs are seeing suspiciously similar tids and request patterns. Combine that with sellers.json monitoring to isolate which resellers are preserving or skewing your tids across paths.

In-app: mediation, bidding, and SDK fragmentation

In-app environments complicate deduplication, because mediation waterfalls and hybrid bidding create multiple request timelines for the same ad opportunity. The rule of thumb is the same: one opportunity equals one tid. The devil is in synchronization. Tactics:

  • Mediation SDK as the source of truth: The mediation layer that orchestrates both bidding and waterfall should generate the tid when a slot becomes eligible and share it with both bidirectional and waterfall adapters.
  • Reuse across parallel bidders, not across waterfall retries: If you fan out to multiple bidding endpoints in parallel, reuse the tid. If the waterfall moves to the next call due to a no-fill, you are now attempting a new sale attempt. Mint a new tid.
  • Slot scoping matters: Distinguish between adUnitId and container context. Two containers on the same screen must not share tids even if they use the same adUnitId in your ad server.
  • Normalize across SDKs: If you integrate network SDKs that cannot accept a source.tid parameter, mirror the tid in a custom extension field and ensure your server-side gateway maps it to the OpenRTB Source.tid field when hitting external demand.

Sample mapping in a gateway:

def to_openrtb_request(sdk_request):
# sdk_request carries sdk_request.tid created by the mediation layer
tid = sdk_request.tid or str(uuid.uuid4())
return {
"id": sdk_request.request_id,
"source": {"tid": tid},
"app": {
"bundle": sdk_request.bundle,
"name": sdk_request.app_name
},
"device": sdk_request.device,
"imp": [{
"id": "1",
"tagid": sdk_request.ad_unit_id,
"banner": {"w": sdk_request.w, "h": sdk_request.h},
"ext": {"tid": tid}
}],
"tmax": 800
}

Coverage guardrail:

  • Waterfall steps are distinct attempts: Do not carry the same tid across 2, 3, 4 retries. Buyers treat repeated tids as duplicates and may suppress the later steps, which hurts fill.

Red Volcano note: Our mobile app discovery and SDK intelligence can help you map which mediation stacks and ad SDKs are in play for a given publisher, and identify where dedup gaps are likely because of unsupported tid propagation in specific adapters.

CTV: SSAI, pods, and distributor complexity

CTV is where tid mistakes become costly fast. SSAI vendors, distributors, and publisher-owned storefronts often create multiple supply paths for the same break. Without care, identical tids are reused across an entire pod or session, or the opposite, entirely different tids are minted for the same slot across partners. Both cost money. Principles for CTV:

  • One tid per pod slot: Mint the tid at the granularity of a single position within a pod, for example the second slot of a 120 second midroll break. Not per pod, not per stream session.
  • Preserve across distributors and resellers: If the same pod slot is offered through the publisher’s own SSP and one or more distributors, use the same tid across those paths. Use schain to reflect the hops.
  • Respect content identifiers: Use OpenRTB 2.6 pod fields and content objects to prevent buyers from over-deduplicating based only on content or timestamp. Make sure the slot-in-pod or sequence attributes are correctly populated.
  • New break, new tids: Every ad break is minted with fresh slot tids. Never reuse a tid across two different breaks or two episodes.

CTV OpenRTB 2.6 snippet for a pod slot:

{
"id": "ctv-req-555",
"source": {
"tid": "8c7e7a6a-5f35-4a5b-8696-4f9f5b6b7f00"
},
"site": null,
"app": null,
"device": {"ifa": "00000000-0000-0000-0000-000000000000"},
"user": {},
"content": {
"id": "content-abc-episode-12",
"title": "Series ABC - Episode 12",
"len": 1800,
"livestream": 0
},
"imp": [
{
"id": "slot-2-in-pod-3",
"video": {
"w": 1920, "h": 1080,
"minduration": 15, "maxduration": 30,
"placement": 1
},
"ext": {
"tid": "8c7e7a6a-5f35-4a5b-8696-4f9f5b6b7f00",
"podid": 3,
"slotinpod": 2
}
}
]
}

Operational tips:

  • SSAI vendors should master tids: The SSAI that stitches ads and controls pod construction is best positioned to mint and assign tids per slot. Downstream SSPs and resellers should preserve them.
  • Distributor alignment: If multiple distributors sell the same feed, agree on a shared tid protocol at ingest. Absent that, use a deterministic mapping from the upstream pod slot token to the tid to ensure stable equivalence across partners.
  • Session and pod independence: Do not include session IDs in tid computation. Keep tids slot specific and ephemeral.

Red Volcano note: Our CTV platform can detect pod and slot structures, correlate bidders that see the same opportunities, and surface where tids are missing or mis-scoped. This is invaluable when reconciling auction coverage against pod delivery.

Reselling and supply chain transparency

Deduplication works best when buyers can recognize the same ad opportunity across the many hands it passes through, without guessing. That is where sellers.json and the SupplyChain object come in. Best practices:

  • Preserve upstream tid: If you are reselling, do not stamp a new tid. Keep source.tid synchronized with the upstream request. Use schain to correctly describe your position in the chain.
  • Complete and accurate schain: Complete equals 1, with nodes that include your domain name, seller ID, and hp flag to indicate if you had payment responsibility. Standard references from IAB Tech Lab and platform guides explain the structure GAM guide.
  • Align sellers.json and ads.txt: Mismatches between the reseller identity and sellers.json entries confuse buyers and increase the chance of path suppression. Keep these in lockstep.

Red Volcano note: Our ads.txt and sellers.json monitors alert when your partners drift from expected transparency, a common root cause when buyers suppress paths that should remain eligible.

Privacy and compliance guardrails

A tidy tid implementation should be privacy neutral. It is still worth stating red lines:

  • No user data in tid: Do not embed or hash user IDs, IPs, or device identifiers into the tid. Use random, non-linkable values.
  • Short lived: Tids should expire rapidly. Avoid logging them for long periods unless necessary for reconciliation, and even then, treat them as sensitive metadata.
  • Consent awareness: The presence of a tid should not override consent frameworks. If certain bidders are disabled due to consent, do not reuse the same tid in a later attempt once consent appears. Mint new tids for new opportunities under new consent scope.

How buyers actually deduplicate in practice

While every DSP has its own logic, patterns are consistent:

  • Primary key: source.tid is the canonical dedup key when present.
  • Fallback heuristics: When tid is absent or unreliable, buyers may fall back to combinations of request ID, slot tagid, page URL or app bundle, and timestamps. This is noisier and increases both false positives and false negatives.
  • Path preference: When duplicates are detected, DSPs often prefer a path with direct seller status, better transparency, or lower take rates, sometimes inferred from schain and historical outcomes.

Implications for sellers:

  • Get tid right, or the DSP will guess. The guess will not be in your favor.
  • Be the path buyers prefer. Invest in clear sellers.json, correct schain, and predictable response behavior.

For additional color on Source.tid in the ecosystem, vendor and community documentation provides pointers, including BidSwitch Source Object and Prebid Server references BidSwitch, Prebid Server.

Putting it together: a seller-oriented implementation checklist

Here is a concrete sequence you can execute with your engineering and Ad Ops teams.

  • Define tid scope policy: One slot instance, one tid. New refresh, new tid. Parallel SSPs for the same instance share the tid.
  • Choose an ID generator: UUIDv4 or cryptographically secure random 128-bit tokens.
  • Wrapper integration: If on web, generate tids in your header bidding wrapper and propagate to both client and server bidders. For in-app, implement tid in the mediation layer. In CTV, make the SSAI the source of truth.
  • Reseller agreements: Contractually require preservation of upstream tid and accurate schain.
  • Logging and QA: Capture source.tid, imp.tagid, request cycle, and partner in logs. Run daily anomaly reports for suspicious reuse and for missing tid on eligible paths.
  • Buyer consultation: Pick your top 3 DSP partners and validate how they use tid. Ask them to share dedup metrics on your supply to calibrate your policy.
  • Transparency hygiene: Keep sellers.json and ads.txt up to date. Keep schain complete and accurate.
  • Privacy review: Confirm no user data leaks into tid. Set data retention limits.

What to avoid: six anti-patterns that cost you money

  • Global pageview tid: Using one tid for all slots on a page. Buyers suppress duplicates and CPMs fall.
  • Sticky refresh tid: Reusing a tid across refreshes, often caused by caching tid at the ad unit config level instead of the request cycle level.
  • Adapter-local tids: Letting each bidder mint its own tid. Buyers cannot reconcile supply paths and will deduplicate using less reliable signals, possibly suppressing more paths than intended.
  • Reseller reminting: Intermediaries that generate a new tid per hop, which breaks dedup and can trigger buyer path penalties.
  • CTV pod-level tids: Using one tid for an entire ad pod or session, which causes suppression across slots and wrecks pod economics.
  • Predictable IDs: Using timestamps or short counters that collide, creating accidental dedup across distinct impressions.

Yield preservation outcomes to track

Instrument before and after changes. The right tid strategy should improve the following KPIs:

  • Effective competition: More distinct bid responses per legitimate auction opportunity, measured as average unique DSPs per auction.
  • Coverage: Higher percentage of slots receiving at least one qualified bid per request cycle, especially on refresh and lazy load events.
  • Clearing price stability: Lower variance in CPM for similar inventory across supply paths, indicating reduced suppression bias.
  • Path diversity with control: Fewer buyer-suppressed paths that should be valid, observable through deal diagnostics and DSP feedback loops.

A practical analytics sketch:

-- Coverage and competition by supply path and tid hygiene
WITH base AS (
SELECT ts::date AS d, source_tid, ssp, site_domain, imp_tagid,
COUNT(DISTINCT dsp) AS unique_dsps,
MAX(CASE WHEN bid_price > 0 THEN 1 ELSE 0 END) AS any_bid
FROM auction_events
WHERE ts >= NOW() - INTERVAL '14 days'
GROUP BY 1,2,3,4,5
)
SELECT d,
AVG(unique_dsps) AS avg_unique_dsps,
AVG(any_bid)::float AS coverage_rate
FROM base
GROUP BY d
ORDER BY d;

Future proofing: what to watch

The transaction ID is one piece of a broader push for clean supply paths and interoperable identity that does not rely on user-level tracking. Signals and standards to keep on your radar:

  • OpenRTB 2.6 adoption: Wider support for pod and interstitial fields improves dedup logic in CTV when populated correctly.
  • Demand-side transparency: Buyers.json and DemandChain object add mirrors on the buy side. While they do not change tid, they influence buyer selection heuristics across paths.
  • Privacy-enhancing tech: As PETs expand, reliably scoping transaction-level identifiers without user linkability remains essential. Keep tid as a clean, ephemeral transaction handle.
  • DSP dedup feature exposure: Some DSPs expose dedup stats to sell side partners. Use that data if available to troubleshoot and tune your policy.

References to learn more include community and vendor guides on OpenRTB Source and schain as well as Prebid Server handling of tid BidSwitch Source Object, Prebid Server features, and transparency explainer pages GAM SupplyChain, IAB Tech Lab FAQ.

How Red Volcano can help

Red Volcano focuses on supply side intelligence. Several of our capabilities map directly to the problem of deduplication without collateral yield loss.

  • Magma Web: Analyze publisher header bidding setups and SSP mixes. Identify where inconsistent tid practices are likely by correlating wrapper, bidder, and ad server configurations.
  • Technology stack tracking: See who runs which wrappers, mediation layers, and SSAI vendors. Prioritize remediation on stacks known to have gaps in tid propagation.
  • Ads.txt and sellers.json monitoring: Keep your transparency stack clean. We flag misalignments that increase the odds of buyer suppression along specific paths.
  • Mobile SDK and CTV intelligence: In-app and CTV are where most dedup failures hide. We surface pod structures, slot behaviors, and SDK footprints that inform where to fix or tighten tid policy.
  • Sales outreach enablement: If you are an SSP or intermediary, use our insights to show publishers where your path is the clean, well deduplicated path buyers prefer.

Conclusion

Deduplicating auctions is good hygiene for buyers and for the ecosystem. The transaction ID makes it possible to reduce waste and improve signal quality. For sellers, the trick is to get the scoping right so that deduplication reduces redundancy without throttling legitimate competition. That means one slot instance per tid, preserved across parallel paths, never reused across distinct opportunities, and kept privacy neutral. Web, app, and CTV each have their own traps. The playbooks here are built to help you avoid them. Couple principled implementation with monitoring and transparency hygiene, and you protect yield while giving buyers the clarity they need. If you are looking for a partner to benchmark your stack, validate your tid hygiene, and find the quickest routes to healthier auctions, Red Volcano can help. Our data products are built for supply side practitioners who care about doing this the right way.

References and further reading