Formatting Pipes
Learn how to format numbers, durations, currencies, and dates in your Twitch overlays using pipe syntax. Zero dependencies, fully locale-aware.
On this page
- Pipe Syntax
- |round - Round numbers
- |number - Locale-aware numbers
- |currency - Currency formatting
- |duration - Time durations
- |date - Date formatting
- |distance - Distance with unit conversion
- |speed - Speed with unit conversion
- |uppercase / |lowercase - Text transforms
- ?? default - Fallback for empty tags
- Locale Settings
- Pipes in CSS
- Tips
- Quick Reference
- More help
No JavaScript required, no external libraries, no build step. Just add a pipe to your tag and you are done.
Pipe Syntax
Add a pipe | after any tag name, followed by the formatter. Some formatters accept arguments after a
colon.
Without formatting: [[[c:score]]]
With a formatter: [[[c:score|round]]]
With a formatter and arguments: [[[c:timer|duration:hh:mm:ss]]]
The pipe is stripped before the tag is resolved. A tag like [[[c:score|round]]] still reads the value
of the score control - the pipe only affects how it is displayed.
Works with all tag types
Pipes work on any template tag - controls, Twitch data, Ko-fi data, StreamLabs data, event data. Anything
between [[[ and ]]] can have a pipe.
Control value: [[[c:amount|currency:EUR]]]
Ko-fi integration data: [[[c:kofi:latest_donation_amount|currency]]]
Event data in alerts: [[[event.user_name|uppercase]]]
|round - Round numbers
Rounds a numeric value. Without arguments, rounds to a whole number. Pass a number to control decimal places.
| Tag | Raw value | Output |
|---|---|---|
[[[c:score|round]]] |
42.789 | 43 |
[[[c:score|round:1]]] |
42.789 | 42.8 |
[[[c:score|round:2]]] |
42.789 | 42.79 |
|number - Locale-aware numbers
Formats a number with thousands separators and decimal notation based on your locale setting. Optionally pass a number to fix decimal places.
| Tag | Raw value | en-US | nl-NL |
|---|---|---|---|
[[[c:viewers|number]]] |
1234567 | 1,234,567 | 1.234.567 |
[[[c:ratio|number:2]]] |
3.5 | 3.50 | 3,50 |
|currency - Currency formatting
Formats a number as a currency value with the proper symbol, decimal places, and separators for your locale.
Without arguments, the currency is determined by your locale (EUR for Dutch, GBP for British, USD for American, etc.). Pass a three-letter ISO 4217 currency code to override.
| Tag | Raw value | en-US | nl-NL |
|---|---|---|---|
[[[c:goal|currency]]] |
42.5 | $42.50 | € 42,50 |
[[[c:goal|currency:EUR]]] |
42.5 | €42.50 | € 42,50 |
[[[c:goal|currency:JPY]]] |
4250 | ¥4,250 | JP¥ 4.250 |
Tip: If your streaming currency differs from your locale's default, just pass the code explicitly. A
Dutch streamer who receives USD donations can use [[[c:kofi:latest_donation_amount|currency:USD]]].
|duration - Time durations
Without arguments, the duration formatter picks the most readable format based on how large the value is. The input is always in seconds.
| Raw seconds | Output |
|---|---|
| 45 | 0:45 |
| 754 | 12:34 |
| 8107 | 2:15:07 |
| 93907 | 1d 2h 5m |
Explicit patterns
Pass a pattern using dd, hh, mm, ss tokens. Time overflows into the largest unit in your pattern.
| Tag | Seconds | Output |
|---|---|---|
[[[c:timer|duration:hh:mm:ss]]] |
8107 | 02:15:07 |
[[[c:timer|duration:mm:ss]]] |
8107 | 135:07 |
[[[c:timer|duration:dd:hh:mm:ss]]] |
93907 | 01:02:05:07 |
[[[c:timer|duration:mm:ss]]] |
45 | 00:45 |
The overflow rule means mm:ss with 8107 seconds gives you 135:07, not 15:07. The hours spill into
the minutes because there is no hh in the pattern.
Tip: Negative values (like a countdown past zero) are supported. The output will be prefixed with
-, e.g. -02:15.
|date - Date formatting
Formats a date or datetime string. Without arguments, shows a locale-aware date and time. Use a named preset or a custom pattern to control the exact output.
| Tag | en-US | nl-NL |
|---|---|---|
[[[c:event_date|date]]] |
Apr 5, 2026, 7:00 PM | 5 apr 2026, 19:00 |
[[[c:event_date|date:short]]] |
Apr 5, 7:00 PM | 5 apr, 19:00 |
[[[c:event_date|date:long]]] |
Saturday, April 5, 2026, 7:00 PM | zaterdag 5 april 2026, 19:00 |
[[[c:event_date|date:date]]] |
Apr 5, 2026 | 5 apr 2026 |
[[[c:event_date|date:time]]] |
7:00:00 PM | 19:00:00 |
[[[c:event_date|date:dd-MM-yyyy]]] |
05-04-2026 | 05-04-2026 |
[[[c:event_date|date:dd-MM-yyyy HH:mm]]] |
05-04-2026 19:00 | 05-04-2026 19:00 |
Available tokens
| Token | Meaning |
|---|---|
yyyy |
Full year |
MM |
Month (01-12) |
dd |
Day (01-31) |
HH |
Hours (00-23) |
mm |
Minutes (00-59) |
ss |
Seconds (00-59) |
|distance - Distance with unit conversion
Formats a distance value with locale-aware number formatting and optional unit conversion. The input is
always assumed to be in kilometers. Pass the target unit as an argument: km for kilometers
(pass-through) or mi for miles.
The unit label is never appended. Add your own label in the template if you want it:
.[[[c:gps:session_distance|distance:km]]] km
| Tag | Raw value (km) | en-US | nl-NL |
|---|---|---|---|
[[[c:gps:session_distance|distance:km]]] |
11.61 | 11.61 | 11,61 |
[[[c:gps:session_distance|distance:mi]]] |
11.61 | 7.21 | 7,21 |
Why km in, any unit out? Overlabels GPS controls store raw distance values in km so your templates are the single source of truth for how distance is shown. Your locale handles number formatting; the pipe arg handles unit choice.
|speed - Speed with unit conversion
Formats a speed value with locale-aware number formatting and unit conversion. The input is always
assumed to be in meters per second. Pass the target unit: kmh for kilometers per hour, or mph for
miles per hour.
The unit label is not appended. Append it yourself if you want it shown.
| Tag | Raw value (m/s) | en-US | nl-NL |
|---|---|---|---|
[[[c:gps:session_max_speed|speed:kmh]]] |
15.5 | 55.8 | 55,8 |
[[[c:gps:session_avg_speed|speed:mph]]] |
15.5 | 34.7 | 34,7 |
Note: c:gps:speed is a legacy control that's pre-converted server-side based on your speed_unit
setting. The newer per-session controls (session_max_speed, session_avg_speed) store raw m/s so the
|speed: pipe is required to render them.
|uppercase / |lowercase - Text transforms
Simple text case transformations. No arguments needed.
| Tag | Raw value | Output |
|---|---|---|
[[[event.user_name|uppercase]]] |
NightBot | NIGHTBOT |
[[[event.user_name|lowercase]]] |
NightBot | nightbot |
?? default - Fallback for empty tags
Add ?? something after a tag to show literal text when the tag resolves empty. Without it, an empty
tag renders nothing - so Hi with no argument becomes [[[bot:args.0]]]!Hi !. A default keeps it
readable.
No value - shows the default:
[[[bot:args.0 ?? everyone]]]
Pairs with a pipe - format when present, default when empty:
[[[c:donations|number ?? 0]]]
The default is literal - spaces and punctuation are kept:
[[[event.user_name ?? a kind stranger]]]
How it behaves
| Tag | Raw value | Output |
|---|---|---|
[[[c:tips ?? 0]]] |
(empty) | 0 |
[[[c:tips ?? 0]]] |
25 | 25 |
[[[c:tips|currency ?? no tips yet]]] |
(empty) | no tips yet |
[[[c:tips|currency ?? no tips yet]]] |
25 | $25.00 |
When a value is present the pipe formats it as usual; the default is only used when the value is empty, and it is shown verbatim (the pipe is never applied to it).
It only fills in for empty. A default backstops a missing value, not a wrong one. If a value is
present - even an unexpected one - it is shown as-is and the default never fires. And like pipes, ?? is
display-only: it never changes a control's stored value or feeds into expression-control math.
Locale Settings
The |number, |currency, |date, |distance, and |speed formatters are all locale-aware. Your
locale controls things like:
- Thousands separator (comma vs period vs space)
- Decimal separator (period vs comma)
- Currency symbol and position
- Date month names and ordering
- Default currency code (USD for en-US, EUR for nl-NL, etc.)
Changing your locale
Go to Settings > Account and pick your locale from the dropdown. You will see a live preview of how numbers, currencies, and dates will look in your overlays.
The locale is applied to all your overlays automatically. Your viewers do not need to do anything.
Pipes in CSS
Pipes work in CSS too - anywhere you can use a template tag, you can pipe it.
<style>
.timer {
/* Hides when timer hits 00:00 */
content: '[[[c:round_timer|duration:mm:ss]]]';
}
.donation {
content: '[[[c:kofi:latest_donation_amount|currency]]]';
}
</style>
Tips
One pipe per tag
Each tag supports exactly one pipe. You cannot chain multiple formatters like
[[[c:score|round|number]]]. Pick the one formatter that gets you closest to what you need.
Pipes are display-only
Formatting never changes the stored value. Your control still holds the raw number - the pipe just changes how the overlay renders it. Two tags referencing the same control with different pipes will display differently but read the same underlying value.
Unknown formatters are ignored
If you typo a formatter name, the value is displayed as-is. No errors, no blank output - just the raw value. Check your spelling if formatting does not seem to apply.
Duration expects seconds
The |duration formatter always expects the raw value to be in seconds. Timer controls already output
seconds, so they work perfectly. If you are feeding in a custom value, make sure it is seconds.
Same tag, different format
You can reference the same control multiple times with different pipes. This is useful for showing the same value in different formats.
<div>[[[c:timer|duration:hh:mm:ss]]]</div>
<div>[[[c:timer]]] seconds</div>
Quick Reference
| Pipe | Arguments | Description |
|---|---|---|
|round |
N (decimal places) | Round to N decimals (default: 0) |
|number |
N (decimal places) | Locale-aware thousands separators |
|currency |
CODE (e.g. EUR, GBP) | Locale-aware currency with symbol |
|duration |
pattern (hh:mm:ss, mm:ss, etc.) | Seconds to human-readable time |
|date |
short, long, date, time, or pattern | Locale-aware date + time formatting |
|distance |
km, mi | Locale-aware distance, input in km |
|speed |
kmh, mph | Locale-aware speed, input in m/s |
|uppercase |
- | ALL CAPS |
|lowercase |
- | all lowercase |
?? text |
literal fallback | Shown only when the tag is empty |
More help
See the Conditional Tags and Controls guides for more on how template tags and controls work. If you are stuck, [email protected] or open an issue on GitHub.