Three ways to embed Zeitful
There are three integration paths, in decreasing order of how common they are. Pick the first one that fits your context; you do not need to mix them.
- iframe embed — the standard path. One
<iframe>tag pointing at/embed/[tool]. Works in almost every CMS and intranet that allows HTML. Free, with a single visible attribution link below the widget. - Direct link with brand attribution — for contexts where you cannot embed at all (email newsletters, printed material, slide decks). Link directly to the tool at
zeitful.com/tools/[slug]with a short "Time tool by Zeitful" line. Common in newsletters that ship plain HTML. - Hosted PRO (white-label) — the embed without the attribution link, served from a custom subdomain. Coming soon. Join the waitlist from the embed gallery.
Quick start
Paste this snippet anywhere HTML is allowed. It renders a live world clock for London and New York that updates every second.
<iframe src="https://zeitful.com/embed/world-clock?cities=London,New%20York"
style="width:100%;height:480px;border:0" loading="lazy"></iframe>
<p style="font:13px/1.4 system-ui,sans-serif;color:#6b7280;text-align:right;margin-top:6px">
Powered by <a href="https://zeitful.com/tools/world-clock">Zeitful</a>
</p>The attribution paragraph below the iframe is required (see Attribution). For an interactive snippet builder that lets you preview before copying, use the embed gallery — every tool page also exposes a builder via the "Embed this" button in the header.
URL parameters by tool
Each tool accepts a set of URL parameters that pre-configure its initial state. All parameters are optional; omitting them falls back to sensible defaults. Unknown or malformed values are dropped silently rather than throwing — the embed always renders.
Parameters marked planned are intended interfaces that ship in a later wave. The shape will not change once stable, so it is safe to write the snippet against them today and have it activate when the feature lands. Parameters marked beta may change before reaching stable.
/embed/world-clock
| Name | Type | Default | Description |
|---|---|---|---|
| cities | string (comma-separated slugs) | san-francisco,new-york,london,berlin,mumbai,tokyo | City slugs as listed in the city directory. Slugs are lowercase, hyphenated (new-york, not NewYork). Unknown slugs are silently dropped. |
| format | "24h" | "12h" | 24h | Clock format. Twelve-hour format renders AM/PM. |
| themeplanned | "light" | "dark" | "sepia" | light | Colour theme. See the theming section below. |
Live preview: /tools/world-clock
/embed/time-zone-converter
| Name | Type | Default | Description |
|---|---|---|---|
| zones | string (comma-separated slugs) | (varies) | City slugs to populate the converter rows. First slug is the default pivot. |
| pivot | string (city slug) | first slug in zones | The reference city whose clock controls the others. Must appear in zones. |
| date | string (YYYY-MM-DD) | today | ISO date the conversion should anchor to. Useful for DST-sensitive dates. |
| time | string (HH:MM, 24-hour) | current time | Time at the pivot to convert. |
| themeplanned | "light" | "dark" | "sepia" | light | Colour theme. |
Live preview: /tools/time-zone-converter
/embed/meeting-scheduler
| Name | Type | Default | Description |
|---|---|---|---|
| zones | string (comma-separated slugs) | (detected) | City slugs to overlap. Two minimum, four typical, no hard cap. |
| pivot | string (city slug) | first zone | Reference city for the suggested-slot output column. |
| date | string (YYYY-MM-DD) | today | Date the search runs against. |
| start | number (0–23, hour of day) | 9 | Earliest acceptable local hour at each zone. Out-of-range values are clamped to 0–23. |
| end | number (0–23, hour of day) | 17 | Latest acceptable local hour at each zone. |
| themeplanned | "light" | "dark" | "sepia" | light | Colour theme. |
Live preview: /tools/meeting-scheduler
/embed/age-calculator
| Name | Type | Default | Description |
|---|---|---|---|
| dob | string (YYYY-MM-DD) | (empty) | Date of birth. Non-matching values (wrong format, future dates beyond a sane range) are ignored. |
| formatplanned | "years" | "days" | "live" | live | Initial display granularity. |
| themeplanned | "light" | "dark" | "sepia" | light | Colour theme. |
Live preview: /tools/age-calculator
/embed/countdown-maker
| Name | Type | Default | Description |
|---|---|---|---|
| to | string (YYYY-MM-DDTHH:MM) | (empty) | Target moment in local time of the chosen timezone. Must match the format exactly. Pair with tz to disambiguate. |
| tz | string (IANA zone, max 64 chars) | browser zone | IANA timezone, e.g. Europe/London. Validated against the runtime's zone database. |
| title | string (max 80 chars) | (empty) | Headline above the countdown, e.g. "Launch day". |
| message | string (max 120 chars) | (empty) | Subtitle below the countdown. |
| themeplanned | "light" | "dark" | "sepia" | light | Colour theme. |
Live preview: /tools/countdown-maker
/embed/pomodoro-timer
| Name | Type | Default | Description |
|---|---|---|---|
| workplanned | number (1–180, minutes) | 25 | Length of each focus block. |
| shortplanned | number (1–60, minutes) | 5 | Length of the short break after each focus block. |
| longplanned | number (1–90, minutes) | 15 | Length of the longer break after a full cycle. |
| cyclesplanned | number (1–12) | 4 | Number of focus blocks before a long break. |
| themeplanned | "light" | "dark" | "sepia" | light | Colour theme. |
Live preview: /tools/pomodoro-timer
Sizing and responsive layout
Every embed assumes width: 100% of its container. Set the height explicitly. The defaults below come from lib/embed/snippet.ts and are the heights the embed builder uses unless you override them.
| Tool | Recommended height | Minimum height | Mobile notes |
|---|---|---|---|
| world-clock | 520 px | 360 px | Single-column at < 480 px. |
| time-zone-converter | 480 px | 320 px | Rows stack; add 60 px per row beyond three. |
| meeting-scheduler | 560 px | 440 px | Heatmap scrolls horizontally below 600 px. |
| age-calculator | 460 px | 320 px | Live ticker stays legible to 320 px. |
| countdown-maker | 420 px | 280 px | Digits shrink fluidly; no scroll needed. |
| pomodoro-timer | 520 px | 400 px | Config drawer collapses on mobile. |
If you go below the minimum, the widget keeps rendering but starts clipping. Above the recommended height the widget centres in the iframe and leaves dead space — no visual harm, but you are wasting screen real estate. The shared snippet generator in lib/embed/snippet.ts defaults to 520 px when nothing is specified.
Aspect ratio. None of the embeds have a fixed aspect ratio. They are content-first: pass any width, choose a height that suits the page, the internal layout adapts. If you need a 16:9 frame for slide-style decks, wrap the iframe in your own aspect-ratio container — do not try to fight the embed.
Mobile breakpoint. Most embeds switch to a single-column layout around 480 px. The world clock and converter add a horizontal scroll for overflow rather than truncating. The meeting scheduler keeps the heatmap visible but horizontally scrollable. If your page renders inside a phone-width column (under 400 px), drop the height by 60–80 px from the recommended values above.
Theming
Pass ?theme= to switch the colour palette. Three themes are supported:
?theme=light— default. Neutral surfaces, ink-grey text. Best on white or near-white parent pages.?theme=dark— inverted. Near-black surfaces, off-white text. Best on dark parent pages or in apps with a system-driven dark mode.?theme=sepia— warm paper. Cream surfaces, slate text. Pairs with editorial and reading-focused parent contexts.
Theming is implemented via CSS custom properties on the iframe's root element. Each theme remaps the same token set so component code is theme-agnostic. The mapping is fixed and not editable from outside the iframe — that is what the themes are for. If none of the three fits your site, link out instead of embedding, or wait for the white-label PRO tier.
| Token | light | dark | sepia |
|---|---|---|---|
| --background | #ffffff | #0b0b0d | #f6efe1 |
| --foreground | #0b0b0d | #f4f4f5 | #3a2a1a |
| --muted | #f4f4f5 | #1c1c1f | #eadfc7 |
| --border | #e5e7eb | #2a2a2e | #d6c9aa |
Status: the ?theme= parameter is documented here as the planned interface. Light is the only theme shipping today. Dark and sepia ship in a follow-up wave. Snippets that include the param today will silently fall back to light until the themes activate, so it is safe to write against this interface now.
Attribution requirement
Every embed must include one visible dofollow link back to zeitful.com/tools/[slug]. This is the entire business model of the free embed tier. If the attribution disappears, the embed loses its only contribution path back to the source.
Acceptable forms.
- Small text link below the iframe, like the example in the Quick start section.
- A "Powered by Zeitful" badge in the host page's footer, provided the embed itself is on that page.
- The Zeitful wordmark, sized so the link is legible at body-text size.
Not acceptable.
- Hiding the link with CSS (
display: none, zero opacity, off-screen positioning). - Putting the attribution only in an HTML comment or in the page source.
- Wrapping the link in
rel="nofollow"orrel="noreferrer". The link must be dofollow. - Routing the link through a redirector that strips referer or attribution.
If you genuinely cannot ship a visible attribution link (white-label intranet, app store reviewer guidelines, contractual restriction), use the PRO tier when it ships. Until then, link out to the tool instead of embedding.
postMessage protocol (optional)
For embedders who want to react to events inside the widget — analytics, conversion tracking, parent-window state sync — Zeitful will emit window.postMessage events from the iframe. The protocol is small, additive, and tied to the URL params so you can rely on stable shapes.
Status: postMessage events are not shipped yet. The shapes below are the planned interface and will not change once they land. Write your listener now and it activates the moment the first event fires.
Planned events:
timekit:loaded— fires once when the embed has hydrated and is interactive. Payload:{ tool: string, version: string }.timekit:converted— for the converter and meeting scheduler. Fires when the user changes the pivot time or zone. Payload:{ tool, pivot, zones, time }.timekit:countdown-complete— fires once when the countdown hits zero. Payload:{ tool: "countdown-maker", target: string }.timekit:resize— debounced; fires when the embed's preferred height changes (e.g. user adds a city). Payload:{ height: number }. Useful if you want to dynamically size the iframe.
Pattern for the listener:
window.addEventListener('message', (event) => {
// Always check the origin to prevent spoofing.
if (event.origin !== 'https://zeitful.com') return;
const data = event.data;
if (!data || typeof data !== 'object') return;
switch (data.type) {
case 'timekit:loaded':
// The embed is ready. Hide your loading skeleton.
break;
case 'timekit:converted':
// The user changed the pivot. Mirror into your analytics if you want.
break;
case 'timekit:countdown-complete':
// Fire a confetti animation, redirect, whatever the moment calls for.
break;
case 'timekit:resize':
// Resize the iframe if you opted into dynamic height.
// const iframe = document.querySelector('iframe[data-Zeitful]');
// if (iframe) iframe.style.height = data.height + 'px';
break;
}
});The origin check is mandatory. Anyone can post a message to your window claiming to be Zeitful; only events from the Zeitful origin should be trusted.
Brand guidelines for embedders
Short and unambiguous because the attribution link is the only place embedders interact with the brand.
- Wordmark. The brand is
Zeitful, capital Z and the rest lowercase. NotZEITFUL, notzeitful. The attribution snippet ships with the correct casing, so leave it alone. - Approved attribution text. "Powered by Zeitful", "Time tool by Zeitful", or "via Zeitful". All three are fine. "Powered by Zeitful" is the default.
- Disallowed wording. Do not invent variants like "sponsored by Zeitful" or "in partnership with Zeitful", neither is accurate. Do not omit the link, even in compact contexts.
- Logo. Wordmark and bug downloads are at
/brand/assets(coming soon). Until then, use the text wordmark in the attribution snippet. - Colour. The embed's internal palette is controlled via the
?theme=parameter. Do not override it with CSS injection or by wrapping the iframe in a stylesheet that targets its descendants — most browsers block this anyway because of cross-origin isolation, but trying to defeat that also violates these guidelines.
Common embedding platforms
Quick how-tos for the platforms we get the most embed traffic from. If your CMS is not listed and the iframe snippet does not just work, the most likely culprit is the platform stripping the <iframe> tag for security. Look for an "HTML", "embed", or "code" block type explicitly.
| Platform | How |
|---|---|
| WordPress | Use the Custom HTML block (Gutenberg) or the Text tab in the classic editor. The iframe snippet pastes in directly. If your theme strips iframes, install the HTML Snippets plugin and paste the snippet as a reusable snippet. |
| Ghost | Insert an HTML card (the + menu in the editor, then HTML). Paste the iframe snippet. Ghost previews iframes inline. |
| Notion | Notion does not allow raw iframes, so use an intermediary like embed.it or webembedplus. Paste the embed URL into Notion as an "embed" block; it routes through the intermediary and renders. For the Notion URL format, copy from the Notion URL tab in the embed builder. |
| Webflow | Use the Embed component (Components panel → Embed). Paste the iframe snippet. Set the parent container width to control how the widget scales on tablet and mobile. |
| Confluence | Use the HTML Macro (Cloud) or Source Editor (Server). Paste the iframe snippet. Confluence Cloud requires the HTML Macro app to be installed by an admin. |
| Squarespace | Add a Code block (Insert → More → Code). Set the language to HTML and paste the snippet. The Squarespace preview sometimes blocks iframes; check the published page rather than the editor. |
| Wix | Use the HTML iframe element (Add → More → HTML iframe). Paste the iframe snippet. Wix wraps the iframe in its own container; set width to 100% inside the snippet and let the Wix container set the outer width. |
Changelog and stability
The promises behind the URL params, in plain language:
- Stable params do not break without notice. Any param documented on this page without a beta or planned tag is stable. Breaking changes ship with a 90-day deprecation notice in the Zeitful newsletter, in the changelog at the bottom of this page, and via a console warning in the iframe itself for the deprecation window.
- Beta params can change. Anything tagged beta is shipping but may change shape, get renamed, or be removed before stable. Use them if you want, but pin the snippet revision somewhere your team can find it.
- Planned params are tomorrow's stable params. Anything tagged planned describes an interface that has been designed but not yet shipped. The shape will not change once it lands. It is safe to write the snippet against it today; the param will be ignored until the feature activates, then take effect on the next iframe load.
- Breaking changes are announced. The Zeitful newsletter is the only channel where deprecations are guaranteed to land. The changelog below is the canonical history.
Changelog
- 2026-05-29. Embed API reference published. Documents every URL param across the six headline embeds, the sizing table, the planned theming and postMessage interfaces, and the brand and attribution rules.