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

  1. Convert both values from strings to numbers with | times: 1
  2. Compare: is the customer above or below the average?
  3. If above, calculate what percentage of the average they’ve achieved
  4. 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 = 500
  • 680 > 500 → true
  • 680 / 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

  1. Both values are converted to decimals with | times: 1.0 — critical for accurate division
  2. Three branches: increase, decrease, or unchanged
  3. Percentage calculation: (difference / baseline) × 100
  4. ceil rounds up and abs ensures a positive number for display
  5. 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_highlight on 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:

  1. Converts both to numbers
  2. Calculates how many points above or below the benchmark the customer is
  3. Displays a message like “Your NPS of 72 is 27 points above the industry benchmark of 45.”
  4. 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 equal

What’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

This site uses Just the Docs, a documentation theme for Jekyll.