What You’ll Learn in This Module
Benchmarking compares a customer’s metric against an industry or cohort average. Gamification uses that comparison to generate motivating, personalized commentary — congratulating strong performers and encouraging those who are below average. This module covers four production-ready patterns: simple above/below benchmarks, quarter-over-quarter change, utilization percentages, and dynamic benchmark dates.
📖 https://school.cast.app/liquid/liquid-library.html#benchmarking-and-gamification-using-liquid
Why Benchmarking Matters in Cast
Telling a customer “Your product usage is 450 sessions” is informative. Telling them “Your product usage is 35% above the industry average for companies your size” is motivating. Benchmarking transforms raw numbers into context — and context drives action.
When built into Cast narrations, benchmarking:
- Makes data meaningful by providing a point of comparison
- Motivates high performers (“Congratulations — you’re in the top tier”)
- Creates urgency for underperformers (“Companies similar to yours average 20% higher usage”)
- Runs automatically — the CS team doesn’t write individual commentary
Pattern 1 — Simple Above/Below Benchmark
The most basic pattern: compare a customer’s metric to an average and branch the commentary.
How it works
{%- assign u = accountUsage | default: 0 | times: 1 -%}
{%- assign a = avgUsage | default: 0 | times: 1 -%}
{% if u > a %}
{%- assign percentage = u | divided_by: a | times: 100 | round: 0 -%}
Your product usage is {{ percentage }}% of the industry average
for companies similar to your size. Congratulations!
{% else %}
Your product usage is below the industry average for companies
similar to your size.
Contact your {{ "CSM" | cast_pronounce }} for ideas on how to
increase your usage.
{% endif %}
Step-by-step
- Convert both values from strings to numbers with
| times: 1 - Compare: is the customer above or below the average?
- If above, calculate what percentage of the average they’ve achieved
- Display encouraging or actionable commentary based on the result
Real Cast example with data
If accountUsage is "680" and avgUsage is "500":
u = 680,a = 500680 > 500→ true680 / 500 * 100 = 136, rounded to 136
Output: Your product usage is 136% of the industry average for companies similar to your size. Congratulations!
⚠️ Guard against division by zero: If avgUsage is 0, the divided_by will fail. Add a check:
{%- if a > 0 -%}
{%- assign percentage = u | divided_by: a | times: 100 | round: 0 -%}
...
{%- endif -%}
Pattern 2 — Quarter-over-Quarter Change
Compare a customer’s metric between two periods and describe the change — up, down, or flat.
{%- assign current = analysis_current_qtr_avg | default: 0 | times: 1.0 -%}
{%- assign previous = analysis_prev_qtr_avg | default: 0 | times: 1.0 -%}
{%- if current > previous -%}
{%- assign pct = current | minus: previous | divided_by: previous | times: 100 | ceil | abs -%}
Compared to the previous quarter, your monthly average increased by
{{ pct }}%. Awesome to see!
{%- elsif current < previous -%}
{%- assign pct = previous | minus: current | divided_by: previous | times: 100 | ceil | abs -%}
Your average monthly usage decreased from the previous quarter by
{{ pct }}%.
{%- elsif current == previous -%}
Your usage level is consistent with the previous quarter.
{%- endif -%}
What’s happening
- Both values are converted to decimals with
| times: 1.0— critical for accurate division - Three branches: increase, decrease, or unchanged
- Percentage calculation:
(difference / baseline) × 100 ceilrounds up andabsensures a positive number for display- The wording changes based on direction — “increased by” vs. “decreased by”
Why times: 1.0?
Without decimal conversion, current | minus: previous | divided_by: previous would use integer division. If current is 520 and previous is 500:
- Integer:
(520 - 500) / 500 = 20 / 500 = 0→ 0% - Decimal:
20.0 / 500.0 = 0.04→ 4%
The integer version silently rounds to zero. Always use times: 1.0 for percentage calculations.
Guard against zero baseline
{%- if previous > 0 -%}
{%- # Safe to calculate percentage change -%}
{%- else -%}
No previous quarter data available for comparison.
{%- endif -%}
Pattern 3 — Storage / License Utilization Percentage
Show what fraction of a reserved capacity a customer is using, with highlighted key numbers.
{%- assign used = LicenseUsed | default: 0 | times: 1.0 -%}
{%- assign reserved = LicenseReserved | default: 0 | times: 1.0 -%}
{%- if reserved > 0 -%}
{%- assign pct = used | divided_by: reserved | times: 100 -%}
{% if pct >= 1 %}
{%- assign pct = pct | round -%}
{% endif %}
This site used {{ used | round: 0 | cast_highlight }} TiBs during this period,
which is {{ pct | append: "%" | cast_highlight }} of your reserved capacity.
{%- if pct > 90 %}
You're approaching full capacity. Let's discuss expanding your allocation.
{%- elsif pct < 50 %}
You have significant unused capacity. Let's explore how to maximize your investment.
{%- endif -%}
{%- else -%}
No reserved capacity on file.
{%- endif -%}
Key techniques
cast_highlighton the two most important numbers — usage and percentage- Conditional
round— only round when the percentage is ≥ 1 (preserving precision for very small values) - Three-tier commentary: over 90% (upsell), under 50% (optimization), or neutral
Pattern 4 — Dynamic Benchmark Date Reference
Include the current month and year as a benchmark timestamp in your narration:
{%- assign benchmarkMMYYYY = "now" | date: "%s" | date: "%B %Y" -%}
Here are your metrics for the {{ benchmarkMMYYYY }} benchmark.
Output: Here are your metrics for the March 2026 benchmark.
💡 Why date: "%s" | date: "%B %Y" instead of just "now" | date: "%B %Y"? Both work, but the double-date pattern ensures you’re working with a normalized timestamp. In practice, "now" | date: "%B %Y" is simpler and produces the same result.
Combining Patterns — A Complete Benchmark Slide
Here’s a full narration that combines multiple benchmarking patterns:
{% comment %} Benchmark Comparison Slide {% endcomment %}
{%- # === Setup === -%}
{%- assign name = contact_first_name | default: "there" -%}
{%- assign company = contact_account_name | default: "your company" | cast_titlecase -%}
{%- assign u = accountUsage | default: 0 | times: 1.0 -%}
{%- assign a = avgUsage | default: 0 | times: 1.0 -%}
{%- assign current = analysis_current_qtr_avg | default: 0 | times: 1.0 -%}
{%- assign previous = analysis_prev_qtr_avg | default: 0 | times: 1.0 -%}
{%- assign benchmark_date = "now" | date: "%B %Y" -%}
Hi {{ name }},
Here's {{ company | cast_apostrophe }} {{ benchmark_date }} performance snapshot.
{%- # === vs. Industry Average === -%}
{%- if a > 0 -%}
{%- assign vs_avg = u | minus: a | divided_by: a | times: 100 | round: 0 -%}
{%- if vs_avg > 0 %}
Your usage is {{ vs_avg | abs }}% {{ "above" | cast_highlight }} the industry average.
Great work!
{%- elsif vs_avg < 0 %}
Your usage is {{ vs_avg | abs }}% below the industry average. Let's discuss strategies
to increase engagement.
{%- else %}
Your usage is right at the industry average.
{%- endif -%}
{%- endif -%}
{%- # === vs. Previous Quarter === -%}
{%- if previous > 0 -%}
{%- assign qoq = current | minus: previous | divided_by: previous | times: 100 | round: 1 -%}
{%- if qoq > 0 %}
Compared to last quarter, your monthly average increased by {{ qoq }}%.
{%- elsif qoq < 0 %}
Compared to last quarter, your monthly average decreased by {{ qoq | abs }}%.
{%- else %}
Your usage has been consistent quarter over quarter.
{%- endif -%}
{%- endif -%}
This single template generates completely different narrations depending on whether the customer is above or below average, improving or declining, or steady.
Common Mistakes
❌ Forgetting to convert strings before comparisons or math:
{% if accountUsage > avgUsage %}
Both are strings — this comparison is alphabetical, not numeric.
✅ Convert first:
{%- assign u = accountUsage | times: 1.0 -%}
{%- assign a = avgUsage | times: 1.0 -%}
{% if u > a %}
❌ Not guarding against division by zero:
{%- assign pct = u | divided_by: a | times: 100 -%}
If a is 0, this errors.
✅ Always wrap division in a zero check:
{% if a > 0 %}
{%- assign pct = u | divided_by: a | times: 100 | round: 0 -%}
{% endif %}
❌ Using times: 1 instead of times: 1.0 for percentage calculations:
{%- assign u = accountUsage | times: 1 -%}
Integer conversion truncates decimals and causes integer division, producing wrong percentages.
✅ Use times: 1.0 for any percentage or ratio calculation:
{%- assign u = accountUsage | times: 1.0 -%}
Try It Yourself
Exercise: Create a benchmark narration for NPS (Net Promoter Score). You have:
nps_score="72"(customer’s score)nps_benchmark="45"(industry average)
Write Liquid that:
- Converts both to numbers
- Calculates how many points above or below the benchmark the customer is
- Displays a message like “Your NPS of 72 is 27 points above the industry benchmark of 45.”
- Adds a congratulations message if above, or an improvement suggestion if below
Click to reveal the answer
```liquid {%- assign score = nps_score | default: 0 | plus: 0 -%} {%- assign benchmark = nps_benchmark | default: 0 | plus: 0 -%} {%- assign diff = score | minus: benchmark -%} {% if diff > 0 %} Your {{ "NPS" | cast_pronounce }} of {{ score | cast_highlight }} is {{ diff }} points above the industry benchmark of {{ benchmark }}. That's a strong signal of customer satisfaction! {% elsif diff < 0 %} Your {{ "NPS" | cast_pronounce }} of {{ score | cast_highlight }} is {{ diff | abs }} points below the industry benchmark of {{ benchmark }}. Your {{ "CSM" | cast_pronounce }} can help identify opportunities to improve customer satisfaction. {% else %} Your {{ "NPS" | cast_pronounce }} of {{ score | cast_highlight }} matches the industry benchmark exactly. {% endif %} ``` Output: `Your NPS of 72 is 27 points above the industry benchmark of 45. That's a strong signal of customer satisfaction!` Key details: - `plus: 0` for NPS (integer values, no decimals needed) - `diff | abs` to show a positive number in the "below" message - `cast_highlight` on the score and `cast_pronounce` on acronyms - Three branches: above, below, and exactly equalWhat’s Next
In Module 20, you’ll see how to chain everything together in a complete Welcome Slide pattern — combining cast_titlecase, cast_apostrophe, cast_pronounce, snippets, benchmarks, and conditional logic into one polished narration.
📖 Official documentation:
- Snippet Library: https://school.cast.app/liquid/liquid-library.html#benchmarking-and-gamification-using-liquid