Skip to main content
Each product has one detail page for pricing, checkout behavior, shipping, fulfillment, subscriptions, SEO, and custom data.

Creating a Product

Click Add Product in the Products list to open the quick-create modal. Enter the essential fields (Title, Code, Type, Classification, Price) and click Create product. You are automatically taken to the full Product Detail Page to complete configuration.

Product Detail Page

Navigate to the Product Detail Page by clicking any product code or title in the Products list. The page uses a persistent tab layout. Changes are saved by clicking Save in the top toolbar.

General Tab

Core product identity, titles, images, descriptions, category assignment, and SEO metadata.

Pricing Tab

Selling price, retail (compare-at) price, currency, and tax settings.

Subscription Tab

Visible only when This is a subscription product is enabled. See Subscriptions Overview for full billing documentation.

Fulfillment Tab

Warehousing, inventory, cost breakdown, SKU categorisation, product specifications, and shipping profile.

How a shipping rate is chosen

A shipping profile (Products → Shipping Profiles) holds two separate rates - Mainland US Cost and International Cost (outside Mainland US) - plus an optional list of per-country overrides. At checkout the buyer’s country selects exactly one of them:
The two rates are independent - neither one falls back to the other. Leaving a field empty does not mean “charge the other rate”. It means free shipping for that region, applied silently with no warning.A profile set to Mainland US $10 with International left blank charges 10intheUSand10 in the US and **0.00 in every other country**. The checkout’s Shipping line renders $0.00 and the order is placed with no shipping charge at all.This is easiest to hit while previewing your own checkout from outside the US: the country field defaults to the visitor’s geolocated country, so the page shows $0.00 shipping and looks broken even though the US rate is configured correctly. Switch the country to United States to see the US rate apply.Fill in both fields on every profile. If you truly do not ship outside the US, restrict which countries the checkout will accept via checkout_settings.countries (see Countries and US states allowlist) instead of leaving International blank.
“Mainland US” means country = US. Alaska, Hawaii and US territories are not separated out - they receive the Mainland US rate. To charge them differently, add a per-country override or a state-specific rate.
A product with no shipping profile assigned also ships free. Assign a profile to every physical product - including upsell and downsell products, which are charged as separate orders - or use the Products list’s bulk Set shipping profile action to apply one to many products at once.

Merchants Tab

Configure product identifiers per payment gateway integration. For each active payment gateway (NMI, Stripe, BuyGoods, ClickBank, etc.) enter the product ID used on that gateway. These are exposed as product | merchantPriceId:'stripe' in templates.

Bonuses Tab

Assign bonus products that customers receive when purchasing this product. Select from products with classification = bonus.

Files Tab

Visible when product type is Digital or classification is Bonus. Add one or more downloadable files:
  • Purpose — Digital or Bonus
  • Title — File display name
  • Description — Optional description
  • Image — Thumbnail image
  • File — Upload or URL
  • Primary — Mark as primary file for this purpose

Courses Tab

Assign courses that customers are automatically enrolled in after purchase.

Attributes Tab

Fill in values for brand-level Product Attributes defined under Settings → Products → Product Attributes. Supports all field types: text, textarea, rich text, number, boolean, date, select, multiselect, color, image URL, file URL, and JSON. Attributes with applies_to = variant are managed per variant in the Variants tab, not here.

Custom Attributes Tab

Legacy unstructured key/value pairs for ad-hoc product metadata (e.g. a download URL or custom flag).
Note: For structured, typed attributes, use the Attributes tab with Product Attribute definitions instead. Custom Attributes are a legacy system.

Variants Tab

Define product variants (e.g. Color, Size) with individual pricing.
  1. Select variant options — Check which brand-level variant options apply to this product (managed under Settings → Variant Options)
  2. Add variants — Each row shows one field per selected option plus Code and Price

Template Reference

All product data is available in ElasticFunnels templates via data functions and filters. Functions are called with {% set x = FunctionName(args) %} or inline. Filters are applied with {{ value | filterName:arg }}.

Product Object Shape

Every product returned by a data function has the following fields:

ProductFile shape

Each item in product_files, digital_files, and bonus_files:

Data Functions

getProduct(code)

Loads a single product by its code for the current brand. Also pre-loads structured attribute values so the attr and attrLabel filters work immediately on the returned object.
Returns: ProductObject | null

getProducts(filters?)

Returns the brand’s products, with optional filters. Products with Show in frontend off are left out unless you ask for them, see Storefront visibility.
Returns: ProductObject[]

getAllProducts()

Returns every product for the brand without filters. Fastest when you need to iterate all products and filter in the template.
Returns: ProductObject[]

getProductCategories(filters?)

Returns product categories. By default returns a full tree ordered by position, then name, with a depth field. Each item: { id, name, position, parent_id, depth? }
Returns: CategoryObject[]

productDownloads(product)

Flattens all downloadable files attached to a product into a single deduplicated array. Useful for rendering download lists on digital product pages.
Each item: { url, title, kind, purpose, extension, mime_type, size, is_primary, sort_order } Returns: DownloadObject[]

productSavings(product)

Returns a structured savings breakdown comparing retail_price to price. Returns null if there is no saving.
Returns: { amount: number, percent: number, amountFormatted: string, percentFormatted: string } | null

subscriptionSummary(product)

Generates a human-readable billing summary string for a subscription product (e.g. "7-day free trial · Every 1 month").
Returns: string

getProductAttributes(filters?)

Returns the brand’s structured attribute definitions. See Product Attributes for details on attribute types and scoping. Each item: { id, name, slug, type, applies_to, options, filterable, visible_on_product_page, required } Returns: AttributeDefinition[]

getProductAttributeValues(product)

Returns all attribute values for a product as a { slug: value } map.
Returns: Record<string, string | number | boolean>

Filters

formatPrice

Formats a numeric price using the brand’s active currency locale.

savings

Computes the saving between retail_price and price and returns a formatted string.
Returns "" when retail_price is not set or not greater than price.

compareAt

Formats retail_price as a “Was $X” string.
Returns "" when retail_price is not set.

pricePerUnit

Divides price by physical_units_per_product to give the per-unit price. Useful for “per bottle” or “per capsule” displays.
Returns: string (float formatted to 2 decimal places)

subscriptionLabel

Short-form billing label. Returns trial info if present, otherwise the billing frequency.
Returns "" for non-subscription products.

merchantPriceId

Looks up the merchant-specific product identifier from merchant_product_ids (configured in the Merchants tab).

attr

Returns the value of a structured attribute by its slug. Only works on products loaded via getProduct (which pre-loads attribute values).
Returns "" when the attribute is not set.

attrLabel

Returns the human-readable label (name) of a structured attribute definition by slug.

product.gallery is a string[] — an array of CDN image URLs. It is always an array (never null or a JSON string). product.has_gallery is true when the array has at least one entry.
Show the primary image with gallery fallback: