Runtime context

The public CTX objects available to hosted Vein templates.

CTX is the data your sections render from. Every hosted page is assembled from sections, and each section declares the objects it reads — ctx.product, ctx.cart, ctx.localization — in its schema's ctx_needs. The host loads exactly what you declared before your template runs; reading an undeclared object is a hard error at render, so a section's data footprint is always visible in its schema.

Use CTX as your only data source. Every object is already shaped for storefront display — localized, market-priced, and identity-safe — so your template renders what it reads without knowing how the platform resolved it. Objects are lowercase snake_case under ctx.

Theme-facing CTX#

Object

What it holds

ctx.shop

Storefront-safe shop identity, currently name and primary_domain.

ctx.menus

Published menu summaries, with full menu trees loaded only when a template asks for a specific menu handle.

ctx.localization

Active locale and baseline/no-prefix locale.

ctx.localization_prompt

Whether the storefront may show a country/language prompt for the current visitor.

ctx.restock_notifications

Notify Me capture rules for the current product and visitor: enabled state, mode, login requirement, and email-input requirement.

ctx.product

The current product page product, including media, options, selected variant state, price, availability, and Notify Me eligibility.

ctx.cart

The current visitor cart: item counts, currency, subtotal when available, and enriched line items when the template requests them.

ctx.wishlist

The visitor's wishlist: enabled, login_required, and item_count always; enriched items (product, variant, availability, purchase state, Notify Me eligibility) when the template requests them.

ctx.reviews

Product-page reviews (declare reviews in ctx_needs): enabled always; stats (average, count, per-star rows) on product routes; reviews.items tier adds the first page of approved items — reviewer names pre-shaped per the store's reviewer_display setting, verified-purchase flags, store responses, and EXIF-stripped photo URLs.

ctx.consent

The visitor's cookie-consent state for the banner: required (this visitor should be asked), given, and the granted categories. Pair it with the consent_give and consent_withdraw actions — the categories are platform-defined, and the visitor chooses.

ctx.forms

Form input constraints for hosted actions (comment, contact, newsletter, review): per field, required and max_length (rune count), plus min_length and max_images where the store's review settings supply them. Bind these to input attributes instead of hardcoding numbers — the platform validates the same values on submit. Declare the forms context need to receive it.

Prices come to you as money values — objects carrying amount and currency_code — ready for the money host filter. There is no separate currency or market object to consult: the resolved currency travels inside every price, and the active locale is in ctx.localization. Products also carry rating ({average, count}) on the product page and on listing cards when the store has reviews enabled — computed from approved reviews only.

Route and action objects#

Some objects appear only on the routes that need them. Product listings expose ctx.products, ctx.collection, and ctx.category. Content routes expose ctx.page or ctx.policy. Blog routes expose ctx.blog_post, ctx.blog, and ctx.blog_category — ctx.blog is the routed listing with items and ready-made pagination, scoped by the category route or the ?tag= query. Vendor, brand, collection-list, and category-list routes expose ctx.vendor, ctx.brand, or the generic ctx.list. Three reads work on any page, no route required: blog_recent gives any section the latest post cards, pages gives the published-page index as {id, title, slug, url} (A to Z, capped at 100), and policies gives every published policy as {id, type, title, slug, url} ordered by type. All carry permalink-correct URLs — footers typically render policies as the legal-links row.

Account and authentication surfaces additionally read ctx.customer, ctx.customer_settings, ctx.form_error, ctx.auth_notice, ctx.auth_form, and ctx.csrf_token. Each is shaped for display and form behavior — a customer object never carries more than the storefront should show.

Storefront kinds#

ctx.storefront.kind is storefront for a normal storefront and b2b for a B2B storefront. B2B renders the same sections with B2B context — see the B2B pages for what changes.

Blog objects#

On the blog post route, blog_post also carries the comments themselves: comments is the first page of approved comments — each {id, author_name, content, created_at} — and comments_total is the full approved count. comments_enabled tells you whether to render the comments block at all, and comments_login_required whether to ask the visitor to sign in instead of showing the guest fields. Pass ?comments_page=2 on the post URL for further pages. Submissions go through the comment_submit form; when the store reviews comments first, the response says so, and the new comment appears once approved.

Blog post cards (blog.items and blog_recent) carry title, slug, url, excerpt, featured_image.url, author_name, published_at, comment_count, and categories[] and tags[] — each ref with name, slug, and url (category refs link to the category page; tag refs to the tag-filtered blog list). The full blog_post adds content (sanitized HTML), seo_title, and seo_description. Cards and posts also carry an author object — {name, bio, avatar_url} — backed by the store's author entity when the post references one, else the plain author_name with empty bio and avatar.

filters (listing routes)#

On listing routes (shop, category, collection) the context carries filters beside products: items[] is the store's enabled filter definitions in merchant order, each with key, label (localized), display_type and values[] — {key, label, count, selected, url}. Counts are LIVE and disjunctive (selecting a value keeps its siblings countable); url toggles that value on the current URL (repeated ?filter.= params, page reset). applied_count and clear_url drive the "clear all" affordance; price carries the narrowed set's min/max in the visitor's currency. Selections narrow products via the same query the grid runs — variant facets (attribute:*) match on a single variant (a black-S + white-M product does not match black AND M).

search (search route)#

On the search route (the configurable search permalink + ?q=) the context carries search: query, placeholder (the merchant's configured prompt), totals per group, and results — products as standard listing cards with pagination (channel-gated, priced, and ?filter.* selections compose with the query), plus content groups (pages, policies, blog_posts, blog_categories, ...) as {title, excerpt, url} cards, limited to the merchant's enabled result types. Disabled search renders the themed 404. ?q= responses are noindexed.