LLM Intent Scoring for Affiliate Link Placement: Paragraph-Level CTR Tests With SubIDs
Placement beats link count — but only if you score paragraphs with a fixed rubric, label each slot with a SubID, and change one variable on the same article before you trust the lift. This is the placement measurement gate. Not LLM product hype. Not a content factory. You score, you label, you move one link, you read SubIDs.
For SubID naming, network parameter tables, and the setup spine, use the SubID tracking guide. This page measures placement CTR with SubID labels.
Prerequisites
Before I trust a placement decision, I want one URL, one slot, one ASCII label, and the rubric. Not a dashboard full of impressions.
Gather these before you touch anything:
- One live URL with existing affiliate links. Pick a page that already gets clicks. High-traffic first, because SubID differentials read faster there. No visit threshold — just more signal per day.
- A map of every current link slot on that page: paragraph location, anchor text, link type.
- The network’s documented SubID key name for that program (
clickref,afftrack,sid,subId1— whatever it is, per the network’s live docs). If your SubIDs are blank or you’re unsure about parameter names, read the SubID/UTM hygiene spine before you build anything. - An opaque label format:
page/campaign/slot— lowercase, URL-safe, no PII. - A fixed LLM rubric prompt that asks only for scores, not rewritten copy. The model grades. You keep, cut, or move.
If you’re about to buy a tracker because someone’s winner list said so, stop. Use the match tool to job SubID guide instead of buying a logo. The decision that matters here is smaller than a purchase order.
Outcome: bench ready. One URL, one slot, one ASCII label, and the rubric written down.
✓ Checkpoint: You can name the exact URL, the exact slot, and the exact SubID key you’ll use.
Kill the More-Links Assumption

Placement failure wears a link-count mask. The first reflex is to add more links or rewrite the whole post. Both are expensive and both avoid the actual problem.
The structural scenario: same offer density, same copy, but different paragraph intent zones. One paragraph is problem-aware — the reader is looking for a solution. Another paragraph is definitional — the reader is still understanding the problem. A link in the first zone gets clicked because it’s the natural next step. A link in the second zone gets ignored because the reader hasn’t reached the buying frame yet.
Adding a fourth link to the introduction doesn’t fix a mismatched link in the middle. Rewriting the whole post erases whatever ranking and trust already exist. Before either of those, fix the placement that’s already there.
This is not a claim about universal CTR percentages or sample sizes. It’s a structural statement: a link placed in a low-intent paragraph is a wasted impression, regardless of how many other links you add. If you want to loop AI into the problem, read the AI placement loop for personalization — but that’s a different job.
Write one failing-placement hypothesis before you change anything:
If the affiliate link in paragraph 4 of
/best-widgets/has low CTR, then moving it from the definitional paragraph to the problem-aware paragraph will change engagement because the surrounding text signals a different intent state.
That’s the lever. Not more links. Not a full rewrite.
✓ Checkpoint: One written hypothesis that names a specific link, its current paragraph, and the intent mismatch you suspect.
Paragraph Intent Rubric: Ask-Only Scores
Paragraph intent means what the reader wants from that exact block of copy. Not what the product does. Not what the article’s overall topic is. What that paragraph signals about the reader’s next action.
The LLM’s job is to grade intent on existing copy. It must not rewrite the copy. Ask-only scores.
A fixed rubric looks like this:
Score each paragraph from 1 to 5 on these dimensions:
- INTENT: How close is the reader to wanting a solution? (1 = just learning, 5 = actively comparing)
- RELEVANCE: Does the surrounding text naturally support a product mention? (1 = forced, 5 = native)
- TRANSITION: Would a link here feel like a next step, not an interruption? (1 = jarring, 5 = seamless)
For each paragraph, return ONLY:
paragraph_id, intent_score, relevance_score, transition_score, one_line_reason
Do not rewrite the paragraph. Do not suggest copy changes.
Run the same rubric on every paragraph, every time. That’s the fixed part. If you change the rubric between pages, you’re not comparing zones anymore.
The model grades. Humans keep, cut, or move. That division matters. An LLM can’t know your commission structure or your audience’s fatigue level. It can produce a consistent, repeatable read of paragraph intent. Use it for that.
If the rubric output disagrees with your judgment, fix the rubric or the labels — not the model brand. The rubric is the instrument, not the vendor.
✓ Checkpoint: The rubric prompt is written, frozen, and you’ve run it on at least one page without asking for copy edits.
Score Paragraphs and Flag Mismatched Links
Take the scored paragraphs and compare each existing affiliate link against its surrounding intent.
A link sitting in a paragraph with a transition_score of 1 or 2 is a mismatch flag. The reader is in the middle of a definition or a caveat, and the link interrupts. Move or remove it.
A link in a paragraph with intent_score 4 or 5 and relevance_score 4 or 5 is a high-intent zone. That’s where the link belongs — if it’s already there, label it and test it. If it’s not there, that’s a candidate move.
Do not invent mismatch failure rates. I won’t give you a universal percentage because your site’s mismatch rate depends on your content, your traffic, and your audience’s reading behavior. What matters is that you write down the flag list:
P4 - intent=2, relevance=2, transition=1 -> link mismatch, candidate for move
P7 - intent=4, relevance=4, transition=4 -> high-intent zone, current link here
P9 - intent=1, relevance=1, transition=2 -> no link, no move needed
That’s the scored page. You now know which links are in the wrong place and which paragraphs are doing the heavy lifting.
For pre-launch pages, you can fold this into the broader bulk affiliate link validation checklist. But this step is for live pages. Score existing copy, not new drafts.
✓ Checkpoint: A written list of paragraph scores with every mismatched link flagged as move or remove, plus the high-intent zones identified.
Instrument Slots With Opaque SubIDs and Parent Context

Every candidate slot gets a unique opaque SubID before you move anything. “Opaque” means the value itself doesn’t reveal meaning to anyone reading the report: p4-slot-a is not opaque; slot-7x2 is opaque enough.
The label format from your prerequisites is page/campaign/slot. Example:
SubID value: subtest-20260904-p4-hiz
Parent context: page=/best-widgets/, campaign=evergreen, slot=p4-high-intent
The parent context is stored with every click event — in your tracker, your spreadsheet, or your server log. No PII in the parameter. page and campaign and slot are first-party labels, not user data.
Append the SubID to the affiliate link exactly as the network expects the key. Wrong key means silent discard — no error, blank column. This is a path failure, not a placement theory. If your SubID column is blank after the click, treat it as instrumentation failure first. The blank SubID diagnostic walks the branch tree — do not rebuild that checklist here.
Watch sticky assignment and label dilution lightly: one slot can amass clicks from a previous test if you reuse the value. Assign a unique label per slot and per test window; don’t let two positions share the same SubID. Rename before you move, not after.
Every slot gets labeled before any move. That way, when you read SubIDs later, you know exactly which placement produced the click, the conversion, and the revenue.
✓ Checkpoint: Every current and planned slot has a unique opaque SubID and a stored parent context, tested with one real click.
Run the One-Variable Same-Article Test
Isolate one variable. Position, anchor, or density. Not a layout redesign.
The hypothesis template:
If we move link X from zone A to zone B, then CTR/revenue-per-visitor will change because Z.
Offer and surrounding copy are held constant.
Offer held constant. Surrounding copy held constant. Same article serves as its own control - you’re not comparing two different posts with different intents and different traffic. Start the CTR clock when the reader reaches the content block that holds the moved link, not from session start, so early exits before that paragraph do not dilute the placement read.
Example:
If we move the affiliate link from paragraph 4 (definitional zone) to paragraph 7 (problem-aware zone),
then paragraph-level CTR will change because paragraph 7 signals higher intent.
Offer and the rest of the copy remain untouched.
Change exactly one thing. If you move the link and also change the anchor text and also add a button, you’ve run three tests at once and learned nothing.
Same-article A/B means you can either run a split test with two versions of the same page (control vs. moved link) or run a staged rollout where the moved link goes live for all traffic and you compare SubID-level performance before/after. The key is that the article’s content and offer do not change — only the slot.
If timing matters, see predictive analytics for offer selection timing. But don’t blur that with this test.
If you’re thinking about NLP funnel work, that’s a separate lane. The chatbot-driven NLP funnel guide covers different ground. Don’t blur this test with chatbot attribution.
✓ Checkpoint: One live same-article test is running with exactly one variable changed, a written hypothesis, and the offer/copy held constant.
Acknowledge the Position-vs-Intent Confound
If you move a link into a higher-intent paragraph and to a different page position at the same time, you cannot isolate which change drove the CTR shift. That is a real confound, not a footnote.
Two ways to separate visibility from intent:
- Scroll-depth segmentation. If the share of readers who reached the paragraph and clicked (or converted) went up, the lift is at least partly intent, not only that more people saw the link earlier. Prefer conversions - or clicks - per reached reader over raw page CTR when you make that claim.
- A second experiment that holds one axis constant. Keep position fixed and change only the surrounding paragraph (or keep the paragraph intent band fixed and change only position) so the variable you name is the one you actually tested.
A result with a named confound is still better than skipping the test. Name the limitation. Do not over-interpret a first before/after as proof that intent alignment alone won.
Guardrail Metrics: Bounce, Scroll, Time
Success without guardrails is theater. A click spike that hides a UX wound is not a win. Before you invent the placement bet, read the page.
Track bounce rate, time-on-page, and scroll depth next to CTR. If moving the link lifts CTR but bounce jumps, you’ve traded clicks for trust. That’s a net loss.
Record all three metrics for the target page, both before the move and during the test. The guardrail answer is binary: did engagement hold while clicks changed?
✓ Checkpoint: Guardrail metrics are written next to your success metric for the test page.
Pre-Test Heatmaps and Session Watch
Find skip zones before you place the bet. Heatmaps show where users scroll and where they stop. Session watch shows what they do immediately before leaving.
Log one observation for the target paragraph: does the audience actually reach paragraph 7, or do they drop off at paragraph 5? A link in a paragraph nobody reads is a decorative link.
✓ Checkpoint: One logged observation about the target paragraph’s visibility before the test.
Low-Traffic Path When A/B Is Underpowered
Underpowered A/B is not a verdict. If your traffic is too low for a formal split test, use staged rollout, observational SubID labels, and qualitative feedback. Do not invoke a universal sample-size law; I won’t give you a magic visit number.
Your path: move the link, let the SubIDs accumulate for about fourteen days as a noise filter (a full weekday/weekend cycle - not a statistical significance law), then read the paragraph-level CTR differential against the control period. If the lift holds across two consecutive fourteen-day windows, replicate the same move on similar articles. Directional signal, clearly labeled as observational. Low traffic just means longer wait or qualitative read.
✓ Checkpoint: Path selected: formal A/B, staged observational, or longer wait. Written down.
This-Week Verification: Score, Label, Move One Link, Read SubIDs

Pick one URL. Score its paragraphs. Label every slot with a unique opaque SubID. Move one link from a low-intent zone to a high-intent zone. Read the SubIDs.
Prioritize a high-traffic page first — more signal per day, not a magic threshold. After the move, wait a defined window; network reporting lag is real. Then export rows and match on SubID value. Aggregate totals will lie to you; match on the label.
If the SubID for the moved slot shows a higher CTR than the old slot’s baseline, you have a directional signal. If it’s flat, that variable wasn’t the lever. Either way, you have a before/after SubID read queued for next week.
If hygiene stalls — blank column, wrong key, stripped query string — go back to the tracking best practices spine before anything else. A blank SubID means you’re reading absence, not performance.
✓ Checkpoint: One URL queued with a scored paragraph map, labeled slots, one moved link, and a defined date to read SubIDs.
FAQ / Troubleshooting
Blank SubID Column
Wrong parameter key or a redirect/WebView strip. Verify the exact documented key for your program and inspect the redirect chain with curl -sIL to find where the query string disappears. Treat blank as path failure, not placement theory. Full branch tree: SubID not showing up diagnostic.
Too Many or Too Few Mismatch Flags
Rubric too strict or labels reused across slots. Fix the rubric definitions or enforce unique SubIDs per slot — not the model brand.
Placement Moved but No Lift
That variable wasn’t the lever. Do not rewrite the post. Queue the next highest-intent slot as your next hypothesis.
When to Stop Using Formal A/B
Use the qualitative/staged path when you can’t accumulate enough data. Move one link, label it, wait a defined window, and read the directional signal.
Next-Week Score, Label, Move Questions
- Which paragraphs scored high intent?
- Which links carried the correct SubID and parent context?
- Which single variable will you move next?