A reader who finishes an article is at a fork: leave, or read something else. Recommendations are how you win that moment — up to three related pages, chosen for the visitor who is standing there, rendered by your own site.
Nothing about them is curated. There is no related-posts list to maintain and no third-party service involved: the matches are computed from the content of your own pages, so a page you publish tomorrow becomes recommendable on its own.
How a page gets picked
Four filters run before anything is ranked, and they are cumulative:
| Condition | Where it is set | What happens if it fails |
|---|---|---|
| The page’s type has Enable Recommendations on | Settings → Page types | The page is never a candidate, on any page |
| The page is published, as of now | The page itself | Drafts and pages scheduled for a future date are excluded |
| The page is not the one being read | Automatic | Excluded — a page never recommends itself |
| The visitor has not already viewed it | Automatic, from the visitor’s own history | Soft — see below |
That last one is a preference, not a hard rule. Leed first tries to fill all three slots from pages this visitor has not seen. If fewer than three qualify, it fills the rest from the closest matches regardless of history, so the widget never renders with one card in it because a regular reader had already read everything good.
sequenceDiagram
autonumber
participant R as Reader's browser
participant P as Your page
participant API as Recommendations endpoint
participant IX as Content similarity index
participant T as Card template on the page
R->>P: Loads a page carrying a recommendations element
P->>P: Waits for the visitor's session to be ready
P->>API: Recommendations for this page
API->>API: Plan allows serving?
API->>IX: Closest pages by content similarity
IX-->>API: Ranked candidates
API->>API: Drop this page, drop pages already read,<br/>drop unpublished and future-dated
API-->>P: Up to three recommendations, as data
P->>T: Fill the card template once per result
Note over P,T: Zero results — the container hides itself,<br/>heading and all
Making pages eligible
Eligibility is a page-type setting: Settings → Page types, then the Enable Recommendations checkbox on the type you want.
Read the direction carefully, because it is the opposite of what most people assume: the checkbox makes pages of that type eligible to be recommended. It does not put a recommendations section on them. Where the cards appear is a template decision, covered below. Blog posts and articles usually want it on; utility and structural types — a login page, a legal notice — usually do not.
The checkbox sits alongside the rest of a type’s configuration in configuring a page type.
Making the cards look right
A recommendation card is filled from a template your site ships, one slot per field:
| Card element | Source field | What to set so it renders |
|---|---|---|
| Link target | The page’s public URL | Nothing — resolved for you |
| Title | The page title | Always present |
| Publish date | The page’s publish date, formatted with your site’s own date format and timezone | Always present |
| Reading time | Derived from the page’s word count and your site’s words-per-minute setting | Always present |
| Summary | The page’s summary | Write one — an empty summary drops the slot |
| Feature image | The page’s feature image | Set one — an empty image drops the slot |
| Labels | The page’s labels | Optional; renders as a list |
| Authors | The page’s authors | Optional; renders each author’s full name |
Rendered, each recommendation is a card carrying the fields in that table in a fixed order — feature image, title, date, reading time, then summary. Three cards sit in a row on a published page; a missing optional field drops its slot rather than leaving a gap.
Where the cards render
Put data-leed-recommendations on the element that should receive the cards. That is the whole placement API: any page with such an element fills it, and a page without one makes no request at all.
- Attribute (supported)
- Shortcode (deprecated)
The attribute goes on the element the cards are appended to — the element’s own contents are left alone, so a heading placed inside the wrapper stays above them.
<section id="related" class="related-reading">
<h2>Related reading</h2>
<div data-leed-recommendations></div>
</section>The old form still works. It renders nothing visible — only a hidden marker naming the element that receives the cards — so you need both the target element and the helper call.
<section id="related">
<h2>Related reading</h2>
<div id="reco-slot" data-leed-recommendations></div>
</section>When there is nothing to recommend
If no recommendations come back, the widget hides itself rather than leaving a “Related reading” heading sitting over an empty box.
Which element gets hidden depends on how you placed it:
- If the receiving element has an
idand a wrapper with the matching{id}-containerexists, that wrapper is hidden — heading and all. This is the long-standing convention, and it is why the id-based form has always been able to hide its own heading. - Otherwise the receiving element itself is hidden, and anything you placed outside it — including a heading — stays visible. Put the heading inside the element if you want it to disappear with the cards.
The hide is applied with !important so it wins against a display utility class on the container.
Measuring whether they work
Every link inside a recommendation card is stamped with hidden UTM context — carried as an attribute on the link rather than as query parameters in the URL, so your recommendation traffic is attributable without ugly links and without breaking anyone’s bookmark:
| Parameter | Value |
|---|---|
utm_campaign | leed |
utm_source | internal |
utm_medium | recommendation |
utm_term | The recommended page’s id |
utm_content | The link’s own text, capped at 100 characters |
Those clicks land in the destination page’s attribution — open the page a recommendation pointed at, and the click shows up as a recommendation channel arrival. That is the right place to look, and the mechanism behind it is described under the hidden UTMs Leed stamps for you.
What you do not get is an impression count: recommendation cards are not element-view tracked, so there is no “shown 400 times, clicked 12” ratio to read. Click-through against the page’s own session count is the closest available measure. A dynamic CTA, which uses the same similarity engine with different rules, is view-tracked — that difference is one of the real reasons to reach for one rather than the other.
Below Growth, and on failure
Two different situations produce exactly the same result for your visitor, by design:
- Below Growth, the endpoint returns an empty list with a success status and never touches the similarity index.
- If the similarity service itself fails, the response is still an empty list rather than an error body.
In both cases the container hides itself and the page renders normally. Nothing is logged to the visitor’s console, nothing is half-drawn, and no upgrade prompt appears on your published site — an upgrade prompt on a customer-facing page would be advertising your billing status to your readers.
The flip side is that “no cards” is ambiguous from the outside. If you are on Growth and expecting cards, walk the four filters at the top of this page in order before suspecting an outage: the page type must be recommendable, the candidates must be published, and the index must have caught up with your last deployment.