Last updated

Affiliate Hydration Cheatsheet

A single storefront page is cached once and served to every visitor — attributed or anonymous. Affiliate-specific values (name, avatar, link URLs) are filled in on the client by the FairShare SDK. This page tells theme authors which variable to use in which context and how to avoid the traps.

The mental model

Under hydration:

  • The rendered HTML is affiliate-independent. It contains placeholders (sentinels, custom elements, or data attributes) where affiliate values would go.
  • The FairShare SDK runs on every page and swaps those placeholders with the resolved affiliate's values.
  • Anonymous visitors (URL has no rep prefix) get the same HTML with fallback values ("home" for URL segments, empty for text).

If you author a theme assuming affiliate values are baked into the HTML at render time, your theme will break under hydration. This page explains what changes.

The three mechanisms

#MechanismUse forExample
1Custom element<fluid-affiliate-*>Text content that displays an affiliate field<span>Hi, <fluid-affiliate-name>friend</fluid-affiliate-name></span>
2Data attributedata-fluid-affiliate-*An HTML attribute value (src, href, alt) that should hold an affiliate field<img data-fluid-affiliate-src="avatar">
3Inline sentinel{{ username }}A rep username embedded inside a string (URL path segment, JSON attribute)<a href="/{{ username }}/shop">

Each mechanism solves a case the others can't:

  • A custom element can't live inside an attribute.
  • A whole-attribute data marker would replace the entire value.
  • The inline sentinel is safe only in attributes dereferenced on user interaction (href, action), not eagerly-fetched ones (src).

Variable reference

Text fields — affiliate name, email, initials, avatar URL, my_site_url

Do not use these in template text or attributes; the raw value only exists on mysite renders.

Use the corresponding custom element:

FieldCustom elementFallback text
Name<fluid-affiliate-name>put default inside the tag
Email<fluid-affiliate-email>put default inside the tag
Initials<fluid-affiliate-initials>put default inside the tag
Avatar URL<fluid-affiliate-avatar>put default inside the tag
MyHub URL<fluid-affiliate-my-site-url>put default inside the tag
<p>Shop with <fluid-affiliate-name>our team</fluid-affiliate-name></p>
<span class="badge"><fluid-affiliate-initials>FA</fluid-affiliate-initials></span>

The element lives in the light DOM (no Shadow DOM) so surrounding theme styles apply normally.

Attribute values — same fields, when used inside src, href, alt

Use a data marker on the host element:

AttributeMarkerFills
Image sourcedata-fluid-affiliate-src="<field>"src
Link hrefdata-fluid-affiliate-href="<field>"href
Alt textdata-fluid-affiliate-alt="<field>"alt
Any textdata-fluid-affiliate="<field>"textContent (when a custom tag isn't usable)

<field> is one of name, email, avatar, initials, my_site_url.

<img data-fluid-affiliate-src="avatar" data-fluid-affiliate-alt="name" />
<a data-fluid-affiliate-href="my_site_url">View store</a>

my_site_url normally resolves to <page-origin>/my/<username>. To point at a different origin (e.g. a preview environment or a whitelabelled domain), add data-fluid-affiliate-base-url on the same element:

<!-- Default: uses the current page's origin -->
<a data-fluid-affiliate-href="my_site_url">View store</a>

<!-- Explicit origin override -->
<a
  data-fluid-affiliate-href="my_site_url"
  data-fluid-affiliate-base-url="https://staging.example.com"
>View store</a>

The SDK resolves the affiliate's my_site_url against the supplied base URL instead of window.location.origin. Only affects my_site_url; other fields ignore this attribute.

URL path segments — {{ username }} and its siblings

For a rep username embedded inside a URL string, use the inline sentinel:

<a href="/{{ username }}/shop">Shop</a>
<form action="/{{ username }}/join">...</form>

{{ username }} compiles to __fluid_affiliate_username__ under hydration. The SDK swaps every occurrence with the resolved rep username, falling back to "home" for anonymous visitors.

Other identifiers:

VariableEmits under hydrationUse for
{{ username }}SentinelPath segments in link/form URLs (e.g., /<username>/shop)
{{ share_guid }}SentinelSharing-link surfaces where a stable identifier is needed
{{ affiliate_guid }}SentinelLegacy alias for share_guid
{{ sharing_id }}SentinelSharing link variants where external IDs override the username
{{ external_id }}Real valueBackend-only surfaces (webhooks, non-cached contexts)

Company URL helpers — company.shop_page_url, company.join_page_url

These already emit URLs with the sentinel baked in when hydration is on:

<a href="{{ company.shop_page_url }}">Shop</a>
<!-- Renders to: <a href="/__fluid_affiliate_username__/shop">Shop</a> under hydration -->

No theme edit is needed. The SDK swaps the sentinel client-side.

Fields that stay real (no hydration)

VariableValue under hydration
{{ affiliate.web_rep_store_enabled }}Real (company-level setting, not per-rep)
{{ affiliate.logged_in_rep_for_store }}Real
{{ affiliate.sign_in_url }} / sign_out_urlReal placeholders ("#") — use client-side JS to populate
{{ company.* }} (except URL helpers above)Real (not affiliate-dependent)

Conditional visibility — the pattern that replaces {% if affiliate.X %}

Under hydration, {{ affiliate.name }} at render time is the placeholder — never blank. So:

          <!-- ALWAYS true under hydration - broken -->
  <span>Hi, {{ affiliate.name }}</span>