Affiliate attribution
How a click on a Gridscoot search result becomes an attributable retailer commission — with full disclosure of where the money flows.
Overview
Gridscoot earns affiliate commission on outbound clicks. The model is pay-on-click— no placement fees, no “ranked higher because they pay more.” The retailer pays the affiliate network on a successful purchase; the network pays us. We never see the customer’s payment.
The click lifecycle
Every outbound click follows the same five-step lifecycle:
- 1. Search request — agent (or browser) calls
search_productsorGET /api/v1/search. The server returns offers withproduct_url(raw retailer URL) plus internal references the search response doesn’t expose directly. - 2. Click mint — when the user (or agent) selects an offer, they hit
/go/[click_id]on Gridscoot. The server mints a uniqueclick_id(BIGSERIAL), logs the click inaffiliate_clickswith a hashed IP + user-agent fingerprint, and 302-redirects to the retailer. - 3. URL building — the redirect URL is the raw
product_urlaugmented with affiliate-network parameters viapackages/attribution/src/url-builder.ts. The exact param set depends on the network (eBay Partner Network, Commission Factory, Amazon Associates AU). - 4. Retailer purchase— the user completes a purchase on the retailer’s site. The retailer’s checkout reads our affiliate cookie / URL parameters and records the attribution.
- 5. Network reporting — the affiliate network reconciles the purchase against our
click_id(echoed back via the network’s tracking param) and credits the commission. We receive the report via the network’s API or CSV export.
URL builder — the per-network detail
Each affiliate network expects different URL parameters. We maintain a central packages/attribution/src/url-builder.ts with one builder per network. Below is the EPN (eBay Partner Network AU) example — same shape applies to the others, different params.
The customid parameter is the round-trip token — we set it to our internal click_id, EPN echoes it back in their commission report, and we reconcile the commission to the click that generated it.
Reconciliation
Reports come back from each network on different cadences (EPN: daily CSV; CF: API poll; Amazon: monthly batch). Reconciliation runs in packages/attribution:
- For each line in the report, parse the
click_id(echoed via network-specific param) - Look up the
affiliate_clicksrow byclick_id - Set
finalised_at+commission_aud+order_id - If
click_idnot found (rare; typically click-id mismatch or impression-without-click), log a structured warn and route tomanual_review_queue
We never see the customer’s payment, shipping address, or PII. The reconciliation report contains only: our click_id, the retailer’s order id, the order subtotal in AUD, the commission rate, and the commission amount. That’s it.
Ranking impact: zero
Affiliate commission rates are stored in retailers.commission_band on the server. They are never read at search-rank time. The full ranking function lives in apps/web/src/lib/search/run-search.ts— search the file for “commission” and you’ll find zero hits.
The two-stage ranking:
- Product ranking — by hybrid_search SQL RPC (pg_trgm + word_similarity + pgvector embedding distance + brand similarity). Affiliate-rate-independent.
- Offer ranking — within a product, offers sort cheapest-total-first (
price + shipping). Ties broken by in-stock first, then feed freshness. Retailer name is a stable tiebreaker for display, not a rank signal.
This is auditable: every search response includes a query_meta.search_method field naming the algorithm by name. The full disclosure is at /rankings.
Disclosure obligations we comply with
AU + global rules we hold ourselves to (verified row-by-row at /compliance):
- ACL § 18 (Misleading or deceptive conduct)— Gridscoot’s ranking algorithm is fully disclosed; no paid placement; data-source advisory shipped on every search response
- ACCC Advertising on Digital Platforms — disclosure of paid relationships — /partners + /about disclose the affiliate model in plain English; outbound click URLs flagged
rel="nofollow sponsored"in markup - ACCC: ranking must not misrepresent merit-based ordering — two-stage sort fully named on /rankings; affiliate commission % explicitly never read at rank-time; this doc is the auditable engineering claim