Animated Countdown GIFs
for Email & Web

Self-hosted timer generator with visual presets, evergreen deadlines, API key auth, and multi-layer caching. Zero external dependencies.

Countdown Timer GIF Demo
preset=dark-boxes · evergreen=1d 2h 30m · live preview

5 built-in styles, fully customizable

Each preset configures colors, fonts, box styles, and separators. Override any parameter via URL.

dark-boxes
dark-boxes
?preset=dark-boxes&time=2026-12-25T00:00:00&key=YOUR_KEY
gradient-cards
gradient-cards
?preset=gradient-cards&evergreen=2h&key=YOUR_KEY
minimal-light
minimal-light
?preset=minimal-light&time=2026-12-25T00:00:00&key=YOUR_KEY
bold-color
bold-color
?preset=bold-color&evergreen=30m&key=YOUR_KEY
transparent
transparent
?preset=transparent&time=2026-12-25T00:00:00&key=YOUR_KEY

Everything you need, nothing you don't

No SaaS fees, no vendor lock-in, no external dependencies. Just PHP + GD.

Digit Boxes

Rounded, gradient, or outlined boxes around each digit group with configurable padding and radius.

:

Separators

Configurable colon or dash separators between DD:HH:MM:SS groups, auto-sized and centered.

Evergreen Timers

Relative countdowns that start from "now". Perfect for landing pages and automated funnels.

🔒

UID Persistence

Pin a deadline to a user ID. First visit saves the deadline, subsequent visits use it.

3-Layer Cache

PHP filesystem cache + Cache-Control headers + CDN edge caching. Most requests never hit PHP.

🔑

API Key Auth

Per-key daily quotas, IP rate limiting. Control who generates timers and how many.

Aa

3 Bundled Fonts

BebasNeue, Inter Bold, Montserrat Bold. All OFL licensed. Auto-layout picks optimal size.

🎨

Background Images

Local or remote images with cover, contain, or stretch fit. Transparent GIF support via chroma key.

🌊

Built for Bursts

Black Friday email to 10,000 subscribers, all opening at once? Same deadline for everyone means one generation for the whole blast. Per-subscriber deadlines (with uid) cost one generation per recipient, but every re-open is free from cache.

Quotas That Make Sense

Daily limits count generations, not deliveries. A campaign-wide deadline served to a million inboxes ticks the counter once. Personalized evergreen deadlines tick once per subscriber. Subscribers re-opening the same email never re-charge the budget.

🛡

Safe Defaults

Per-key caps on image size and animation length. Remote backgrounds blocked unless you opt in for a specific key. Origin protected against header spoofing when behind a CDN.

Deploy in 3 steps

No Docker, no build tools, no database. Just clone, configure, and point your web server.

1

Clone the repository

Get the source code and set up API keys.

2

Create cache directories

The filesystem cache needs writable directories owned by your web server user.

3

Point your web server

Configure Caddy, nginx, or Apache with PHP-FPM to serve the project directory.

Recommended: deploy with StackPilot

StackPilot handles everything automatically: PHP-FPM, API key generation, cache directories, cleanup cron, Caddy config, Cloudflare DNS and CDN cache rules.

./local/deploy.sh countdown-timer --ssh=vps --domain=timer.example.com

Or set up manually:

# 1. Clone the repository git clone https://github.com/jurczykpawel/countdown-timer.git cd countdown-timer # 2. Generate an API key (creates keys.json with a random master key) bash setup-key.sh # 3. Create cache directories (used for GIF caching and rate limiting) sudo mkdir -p /var/cache/timer-gif/{ab,ev,uid,apikeys,ratelimit} sudo chown -R www-data:www-data /var/cache/timer-gif # 4. Point your web server (Caddy example) # timer.example.com { # root * /path/to/countdown-timer # php_fastcgi unix//run/php/php-fpm.sock # file_server # }

API keys and persistent evergreen

API Key Authentication

All GIF generation requires a valid API key. Add &key=YOUR_KEY to every request. Keys are stored in keys.json, and you can give different keys different power levels.

<!-- Embed in email or web page --> <img src="https://timer.example.com/?preset=dark-boxes &time=2026-12-25T00:00:00 &key=YOUR_KEY" alt="Countdown">

Tier your keys for different audiences. Tight clamps for public newsletters, full power for internal tools:

// keys.json { "tk_master_xyz": { "limit": 0 }, // unlimited internal key "tk_newsletter": { "limit": 5000, // 5k generations / day "max_width": 640, // clamp huge requests "max_seconds": 30 // shorter animations }, "tk_landing_page": { "limit": 50000, "allow_remote_bg": true, // opt in to remote bgs "bg_domains": ["cdn.mybrand.com"] // only your CDN } }

Persistent Evergreen (UID)

Normal evergreen timers reset on every page load. Add a uid parameter to pin the deadline to a specific user. First request saves the deadline, all subsequent requests count down to the same moment.

<!-- Deadline persists per UID --> <img src="https://timer.example.com/?preset=dark-boxes &evergreen=2h &uid=subscriber-uuid-123 &key=YOUR_KEY" alt="Countdown">

URL parameters

All parameters are passed as URL query strings. Presets set defaults that individual parameters can override. Per-key limits in keys.json clamp these values before generation, so a public key can't request a 1200×400 timer with a remote background.

ParameterDescriptionDefault
key requiredAPI key for authentication-
presetNamed preset (dark-boxes, gradient-cards, minimal-light, bold-color, transparent)-
timeAbsolute target datetime (e.g. 2026-12-25T00:00:00)now
evergreenRelative duration (e.g. 2h, 1d 2h 30m, 90m)-
uidUnique ID for persistent evergreen deadline-
tzTimezone (e.g. Europe/Warsaw)UTC
widthImage width in pixels (100-1200)640
heightImage height in pixels (40-400)140
secondsAnimation frames / duration (1-120)30
boxColorBackground color (hex without #)000
fontColorDigit color (hex)fff
fontFont: BebasNeue, Inter-Bold, Montserrat-BoldBebasNeue
fontSizeDigit font size in px (omit for auto)auto
boxStyleBox style: rounded, gradient, outline, nonenone
boxBgBox background color (hex)2d2d4a
boxRadiusBox corner radius in px10
boxPaddingPadding inside boxes in px12
separatorSeparator between groups (: or - or empty):
sepColorSeparator color (hex)fontColor
labelColorLabel text color (hex)fontColor
bgImageBackground image (URL or local path)-
bgFitBackground fit: cover, contain, stretchcover
transparentTransparent background (1 or true)false

Where countdown timers drive results

💰

Limited-time offers

Add urgency to flash sales and promotional emails. Set available_until on your product, embed the timer in your campaign.

🎓

Course launches

Countdown to enrollment close. Use UID persistence so each student sees their personal deadline, even after reopening the email.

🎥

Webinar registration

Drive signups with a live countdown. Absolute timer synced to the event start. Embed in email, landing page, or social media.

Part of the Sellf ecosystem

Countdown Timer is a standalone tool, but it works best with other projects from the same author.