Skip to content

Module 19: Pattern — Benchmarking

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

Section titled “Pattern 1 — Simple Above/Below Benchmark”

The most basic pattern: compare a customer’s metric to an average and branch the commentary.

{% raw %}
{%- assign u = accountUsage | default: 0 | times: 1 -%}
{%- assign a = avgUsage | default: 0 | times: 1 -%}
{%- 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.
{% endraw %}
  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

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:

{% raw %}
{%- if a > 0 -%}
{%- assign percentage = u | divided_by: a | times: 100 | round: 0 -%}
...
{%- endif -%}
{% endraw %}

Compare a customer’s metric between two periods and describe the change — up, down, or flat.

{% raw %}
{%- 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 -%}
{% endraw %}
  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”

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.

{% raw %}
{%- if previous > 0 -%}
{%- # Safe to calculate percentage change -%}
{%- else -%}
No previous quarter data available for comparison.
{%- endif -%}
{% endraw %}

Pattern 3 — Storage / License Utilization Percentage

Section titled “Pattern 3 — Storage / License Utilization Percentage”

Show what fraction of a reserved capacity a customer is using, with highlighted key numbers.

{% raw %}
{%- 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 -%}
{%- assign pct = pct | round -%}
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 -%}
{% endraw %}
  • 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

Section titled “Pattern 4 — Dynamic Benchmark Date Reference”

Include the current month and year as a benchmark timestamp in your narration:

{% raw %}
{%- assign benchmarkMMYYYY = "now" | date: "%s" | date: "%B %Y" -%}
Here are your metrics for the {{ benchmarkMMYYYY }} benchmark.
{% endraw %}

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

Section titled “Combining Patterns — A Complete Benchmark Slide”

Here’s a full narration that combines multiple benchmarking patterns:

{% raw %}
{% 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 -%}
{% endraw %}

This single template generates completely different narrations depending on whether the customer is above or below average, improving or declining, or steady.


Forgetting to convert strings before comparisons or math:

{% raw %}
{% endraw %}

Both are strings — this comparison is alphabetical, not numeric.

Convert first:

{% raw %}
{%- assign u = accountUsage | times: 1.0 -%}
{%- assign a = avgUsage | times: 1.0 -%}
{% endraw %}

Not guarding against division by zero:

{% raw %}
{%- assign pct = u | divided_by: a | times: 100 -%}
{% endraw %}

If a is 0, this errors.

Always wrap division in a zero check:

{% raw %}
{%- assign pct = u | divided_by: a | times: 100 | round: 0 -%}
{% endraw %}

Using times: 1 instead of times: 1.0 for percentage calculations:

{% raw %}
{%- assign u = accountUsage | times: 1 -%}
{% endraw %}

Integer conversion truncates decimals and causes integer division, producing wrong percentages.

Use times: 1.0 for any percentage or ratio calculation:

{% raw %}
{%- assign u = accountUsage | times: 1.0 -%}
{% endraw %}

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
{% raw %}
{%- assign score = nps_score | default: 0 | plus: 0 -%}
{%- assign benchmark = nps_benchmark | default: 0 | plus: 0 -%}
{%- assign diff = score | minus: benchmark -%}
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.
{% endraw %}

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

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: