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.

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.

# 1. Clone and configure git clone https://github.com/jurczykpawel/countdown-timer.git cd countdown-timer cp keys.json.example keys.json # Edit keys.json - add your API key # 2. Create cache directories sudo mkdir -p /var/cache/timer-gif/{ab,ev,uid,apikeys,ratelimit} sudo chown -R www-data:www-data /var/cache/timer-gif # 3. Caddy config example # timer.example.com { # root * /var/www/timer # php_fastcgi unix//run/php/php-fpm.sock # file_server # }

One-liner with StackPilot

If you use StackPilot for VPS management, deploy with a single command:

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

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 with per-key daily quotas.

<!-- 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">

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.

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