Blog · Protocol

source.tid vs imp.ext.tid is the transaction and one impression inside it, not a single tid column.

People say tid and mean three different strings. source.tid is the transaction on one request. imp.ext.tid is one impression inside that transaction. imp.id is neither. A column named tid joins auctions that never shared an id.

source.tid is the request, and it is not automatic across paths

The bid request marks source.tid as the transaction id common across participants in that auction. It is recommended, not invented by the exchange after the fact. Prebid can set it from ortb2. A TAM request and an Open Bidding request for what a human calls the same slot carry the ids those platforms put on their own bodies. They share source.tid only when you passed the same string into each assembly. The three assemblies are why a single debug log lies.

Joining those paths on source.tid when you did not set it fails open. The rows do not share a tid, so they look like separate auctions, which they are. Averaging them into one request is the reporting bug. Capture the tid per path and expect them to differ. A page refresh mints another transaction unless your code reuses the value on purpose.

There is no spec field that is just tid at the top of the request. If a log pipeline says tid, name the path it read. source.tid and a copy someone parked on an extension are not the same key. Buyers and exchanges that read the recommended field will not see the extension.

imp.ext.tid is one slot, and imp.id will not substitute

imp.ext.tid scopes the id to one impression inside the transaction. A request with three impressions can share one source.tid and carry three impression tids. Collapsing them to the transaction id hides which slot cleared. Collapsing them to imp.id is worse: imp.id is required and unique inside the request, and it is often 1, 2, 3. It is not stable across refreshes or across paths. Joining on imp.id joins unrelated auctions that numbered their first slot 1. Bids copy that value to impid.

imp.tagid is the placement the publisher means, the ad unit or slot name. It joins paths only when each assembly was given the same string. A Prebid ad unit code does not become a TAM slot name, and neither becomes the ad server path, unless you set tagid yourself. A prefix one platform adds makes one slot look like three placements.

Store three columns if you need all three scopes: source.tid, imp.ext.tid, and imp.tagid. Store imp.id beside them as the in-request key for the bid, and do not use it as the join across hops. The bid request reference lists source.tid as the shared transaction id. The extension on the impression is how you keep the slots apart inside it.

The bid response does not invent the transaction id

bid.impid points at imp.id for the impression that was bid. It does not point at source.tid or imp.ext.tid. A reporting join from the win notice back to the request has to have stored those fields when the request was sent. The notice macros identify the auction the exchange ran. They are not a substitute for the tid you failed to put on the request.

Two impressions in one request share source.tid and must not share imp.ext.tid if you are using the extension to tell slots apart. Two requests in one page view, a refresh or a second path, must not share source.tid unless you deliberately reused it. Reuse is a product decision. Accident is how dedup collapses two auctions into one, or how one auction splits into three in the log.

Validate that the builder writes source.tid as a string on source, not as a number and not only on the impression. Then decide whether imp.ext.tid is in your contract. If it is, generate it per impression from the same function that builds imp.id, and do not set them equal unless you have decided one id is enough and documented which field partners read.

What to log

  • source.tid per request path. Do not assume TAM or Open Bidding copied the Prebid value.
  • imp.ext.tid when one transaction has more than one impression.
  • imp.id only to match bid.impid inside that response.
  • imp.tagid only if you set the same string on every path you want to join.
  • A column named tid without a path is not a key. Name the field you read.

A refresh and a second path are new transactions

A page that refreshes the ad unit builds another request. Unless the code copies the previous source.tid on purpose, the new request has a new transaction id. Treating the refresh as the same auction double-counts or under-counts depending on which log you trust. Write the reuse rule down. Do not discover it from a join that almost works.

imp.ext.tid follows the impression, so a multi-slot request needs one per imp if you use it. Reusing source.tid for every imp is correct. Reusing one imp.ext.tid for every imp hides the slot. Reusing imp.id values of 1, 2, 3 across paths hides nothing and matches everything. Keep those three ideas in different columns.

Further reading