dashboard.liquid tags are grouped by default vs optional usage.
- Default components are already present in the shipped
dashboard.liquidtemplate. - Optional components can be added or used to replace parts of the default layout.
{% legacy_navbar %}.
Default components
ReferralCandy banner
The defaultdashboard.liquid template includes a ReferralCandy banner when subscription.referral_candy.url is available for the current subscription.
The default banner:
- Links More info to the customer’s ReferralCandy invite page (
subscription.referral_candy.url) - Copies the customer’s ReferralCandy invite link from
subscription.referral_candy.url - Shows the configured advocate reward discount from
subscription.referral_candy.advocate_reward_discountwhen Firmhouse can resolve a valid reward for the subscription - Falls back to a generic translated message when the reward discount is unavailable
subscription.referral_candy.url is only available when Firmhouse can fetch an invite link from ReferralCandy for the subscription. If the ReferralCandy campaign is stopped, paused, or configured in a way that prevents invite links from being created, the value is blank and the default banner stays hidden.
{% prepaid_renewal %}
Prepaid renewal notice and call to action.
The default dashboard.liquid template includes this tag. It renders a renewal block for prepaid subscriptions when the renewal date is coming up and the prepaid subscription was created from a regular subscription through a prepaid upgrade.
Customers can open the renewal options page from this block. On that page, they can keep renewing prepaid, switch back to the original regular billing subscription, or update the renewal payment date without changing their renewal option.
{% simple_next_billing_date_with_confirm %}
Inline editable next billing date control.
| Parameter | Type | Default |
|---|---|---|
show_label | Boolean | false |
{% simple_plan_switch_with_confirm %}
Inline plan switch select with confirmation modal.
| Parameter | Type | Default |
|---|---|---|
label_format | String ("frequency", "plan_name", "both") | "frequency" |
label_format: "both" combines plan name and frequency:
{% manage_products %}
Primary CTA to manage existing products.
| Parameter | Type | Default |
|---|---|---|
size | String ("small"/"large") | "small" |
button_text | String | "Manage products" |
{% product_quantity_progress %}
Progress and status widget for plan-based product quantity rules.
This component only renders when the active plan has a minimum and/or maximum product quantity configured.The default
dashboard.liquid already includes this tag, and you can move or add it elsewhere in the template.
| Parameter | Type | Default |
|---|---|---|
rail_background_color | String (CSS color) | #E5E7EB |
rail_fill_color | String (CSS color) | nil (auto based on state) |
ready_fill_color | String (CSS color) | #16A34A |
pending_fill_color | String (CSS color) | #F59E0B |
over_limit_fill_color | String (CSS color) | #EF4444 |
{% product_listing %}
Main list of active ordered products.
| Parameter | Type | Default |
|---|---|---|
show_delete_button | Boolean | true |
show_quantity_selector | Boolean | true |
show_swap_button | Boolean | true |
{% next_order_price_overview %}
Core upcoming-order summary card.
| Parameter | Type | Default |
|---|---|---|
items | String or Array | recurring_subtotal,one_time_subtotal,discount,shipping,total |
show_discount_code_entry | Boolean | true |
show_discount_code_entry is enabled, the component shows a discount code field below the order summary. Customers can enter an active Firmhouse discount code and apply it to their subscription. After a valid code is applied, the upcoming order totals refresh automatically.
Enable discount code entry
Turn on Discount Codes in Customer Portal v2 in New Features for the project. The default Customer Portal v2 dashboard currently renders this component withshow_discount_code_entry: false. Remove that parameter or set it to true in your custom dashboard.liquid template if customers should be able to apply discount codes from the portal.
Accepted discount codes must meet these conditions:
- The discount code is active and has not reached its usage limit.
- The linked promotion is active and available for the customer’s country.
- No other discount code promotion is already active for the subscription.
- The code is not a referral discount code. Referral codes are intended for new customer signup and first-order discounts, not recurring orders for existing customers.
- For Shopify subscription contracts, the promotion should have simple rules to be synced to Shopify as a subscription contract discount. Codes for more complex Firmhouse-only advanced promotion rules are not supported yet.
{% add_product %}
Secondary CTA to browse catalog and add products.
| Parameter | Type | Default |
|---|---|---|
size | String ("small"/"large") | "large" |
button_text | String | "Add product" (size: "large"), "Add products" (size: "small") |
Optional components
{% latest_orders %}
Recent orders list.
| Parameter | Type | Default |
|---|---|---|
limit | Number | 3 |
{% next_order_preview %}
Upcoming order preview card.
{% product_listing_filtered %}
Filtered product list card (for segmented subscriptions).
| Parameter | Type | Default |
|---|---|---|
filter_by | String | nil |
filter_value | String | nil |
title | String | nil |
show_add_button | Boolean | false |
add_button_text | String | nil |
show_manage_button | Boolean | false |
manage_button_text | String | nil |
show_delete_button | Boolean | true |
show_quantity_selector | Boolean | true |
show_swap_button | Boolean | true |
Dynamic groups based on ordered product metadata
If yourfilter_value should adapt to subscriber-specific metadata (for example names like "Veronika" or "Michiel"), you can build the group list from subscription.ordered_products and then render product_listing_filtered in a loop.
How are dynamic values fetched?
You can do this directly indashboard.liquid; no custom backend endpoint is required.
subscription.ordered_productsis available in SSCv2 Liquid context.- Each
ordered_productincludesmetadata. - Reading
ordered_product.metadata.groupgives the current subscription’s group value for that ordered product (or useordered_product.metadata.personif your project still uses the legacy key). - Pass
filter_bywith the same metadata key (grouporperson) that produced the value. - Looping over ordered products lets you discover all group values present on the active subscription at render time.
- hardcoded sections stay explicit (
Add-ons,Gifts,One-time extras) - dynamic sections include only metadata values currently present on the subscription
- hardcoded values are excluded from the dynamic loop
- exclusions and de-duplication are done case-insensitively (
downcase)
ordered_product.metadata.group (and optional ordered_product.metadata.person fallback) with your key and pass that same key to filter_by.
Shopify instalment progress from ordered products
If your Shopify subscription setup uses instalment billing, you can render progress directly from the ordered products indashboard.liquid.
ordered_product.instalment_current_numberreturns the current instalment number for that subscription line.ordered_product.instalment_total_countreturns the total instalment count from the subscription’s active plan.subscription.active_plan.instalmentsis also available when you want to render plan-level instalment details outside the ordered product loop.
{% next_shipment_date %}
Localized next shipment date text.
{% minimum_contract_duration %}
Commitment/contract duration block.
| Parameter | Type | Default |
|---|---|---|
variant | String ("full", "label", "date") | "full" |