CountUp.js

~5kb gzipped

Animate numbers with easing and locale-aware formatting.


01

See It in Action

Each demo animates a different number. Scroll-triggered stats, live currency conversion, and a pricing-plan switcher -- all with the same tiny API.

Four stats counting up when you scroll the block into view. IntersectionObserver triggers CountUp.start() once per stat.

Preview

02

What is CountUp.js?

CountUp.js animates a number from one value to another, with easing and locale-aware formatting. Give it a DOM element, a start, and an end, and it handles the timing, separator placement (1,000 vs 1.000), decimal precision, and prefix/suffix characters ("$" or "%").

It is the default "animated counter" you see on marketing hero sections ("10M+ users") and dashboards. ~5kb gzipped, zero dependencies, an actively maintained API that has been stable for years. Pair it with IntersectionObserver to trigger on scroll-into-view, or with an input listener for a live currency converter.

🔢
Animate Any Number
Count up, count down, or count to a new target from any starting value. Integers, decimals, currency -- CountUp handles them all.
🌍
Localized Formatting
Built-in separators and decimals use the browser locale. Pass a prefix ("$") or suffix ("%", "k", "M") to get proper money, percentages, or abbreviated counts.
⏸️
Start / Pause / Reset / Update
Full control over the animation lifecycle. Retrigger on scroll-into-view, restart on input change, or chain multiple counters together.

03

When to Use CountUp.js

Use when
Stats grids on marketing pages ("10M+ users", "2.4K sites")
Animated prices on pricing-plan selectors
Live currency-conversion widgets tied to an input
Dashboard counters that animate on data refresh
Onboarding progress meters and score displays
Avoid when
Text that does not change to a different value -- just render the text
Stock-ticker-style continuous updates (hundreds per second) -- performance overhead adds up
Complex typographic animations -- use Split-type + GSAP instead

04

How CountUp.js Compares

CountUp.js vs Odometer.js

Odometer is the classic 'slot-machine' roll-over effect with themed CSS. CountUp is a simpler smooth-counting approach. Pick Odometer when you want the visible digit-by-digit roll; pick CountUp when you want a smooth ease-out to the target.

CountUp.js wins at
Smooth easing curves (easeOutExpo by default), more API control, decimal precision, locale formatting, smaller bundle
Odometer.js wins at
Visible digit-roll effect that looks like a slot machine, built-in CSS themes, more dramatic visual
CountUp.js vs GSAP tween on an object

GSAP can tween any property of an object and you can update DOM text inside onUpdate. More flexible but 40kb larger and more code for the counting case. Use GSAP if you are already using it; pull in CountUp for a standalone counter.

CountUp.js wins at
Zero-config counter helpers (prefix, suffix, separator, decimal), 5kb, no other library needed
GSAP tween on an object wins at
Any easing curve, timeline integration, scroll-trigger integration, animate any property (not just numbers)
CountUp.js vs Writing a setInterval counter

You can write a counter in 10 lines of JS: setInterval + linear increment. CountUp is better because of easing, locale-aware formatting, and correct decimal handling. Small-feature libraries exist to handle the edge cases your hand-rolled version will hit.

CountUp.js wins at
Smooth ease-out instead of linear, correct separators per locale, decimal precision without floating-point artifacts, proper start/pause/reset
Writing a setInterval counter wins at
Zero dependency, absolutely minimal code, full custom control

05

Get Started with CountUp.js

Terminal
npm install countup.js
Terminal
yarn add countup.js
HTML
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/countUp.umd.min.js"></script>
Quick Start
<div id="counter">0</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/countUp.umd.min.js"></script>
<script>
  // The UMD global is countUp (lowercase); the class is countUp.CountUp.
  const c = new countUp.CountUp("counter", 2450000, {
    duration: 2.5,
    separator: ",",
    prefix: "",
    suffix: "+"
  });

  if (!c.error) {
    c.start();
  } else {
    console.error(c.error);
  }

  // Later, animate to a new value:
  // c.update(3100000);
</script>

06

Related Libraries