Put the live sky on your website
An astronomy club homepage that shows tonight's Moon. A blog sidebar counting down to the next eclipse. A school site with sunrise and sunset for its own courtyard. All of these are one of the recipes below, and every one of them is free.
There are five ways in, cheapest first. They all draw from the same engine, so a widget and a hand-built panel will never disagree.
Recipe 1: two lines of HTML
The classic embed: a link that upgrades itself into a live, sandboxed card. Paste this where the widget should appear:
<a class="cyclecalcs-widget" data-widget="moon" data-theme="auto" data-size="card" href="https://www.cyclecalcs.com/moon-phase-calendar.html">Moon phase today - CycleCalcs</a> <script async src="https://www.cyclecalcs.com/embed.js"></script>
data-widget takes moon, tonight, sun, parade, eclipse or cosmic; data-theme is auto, light or dark; data-size is compact, card or wide. Add data-lat and data-lon to pin a location. The embed builder writes all of this for you, with a live preview and your own place baked in. If the page never runs scripts, the link still works: that graceful failure is the design.
Recipe 2: the no-iframe moon widget
The newer moon widget renders directly into your page in a shadow root: no iframe, zero layout shift by construction, and it flips the disc for southern-hemisphere visitors when your data-lat is negative.
<a href="https://www.cyclecalcs.com/moon-phase-calendar.html" class="cyclecalcs-moon" data-size="card" data-theme="auto" data-lat="39.74" data-lon="-104.99" data-place="Denver, Colorado">Tonight's moon, by CycleCalcs</a> <script async src="https://www.cyclecalcs.com/widget.js"></script>
Recipe 3: WordPress
Today: paste either snippet above into a Custom HTML block and it works as-is. If your host strips script tags (common on locked-down or hosted plans), use the plain iframe variant from the embed builder's code panel, which needs no JavaScript at all. A dedicated plugin, with a [cyclecalcs] shortcode and a Gutenberg block over the same loaders, is built and tested and headed for the plugin directory; the developer hub tracks its status.
Recipe 4: React, Vue, Svelte, or none
The widget ships as a custom element on npm, so it drops into any framework's JSX or template unchanged:
# install
npm install cyclecalcs-widget
import 'cyclecalcs-widget'; // defines <cyclecalcs-widget>
<cyclecalcs-widget widget="moon" size="card" theme="auto"></cyclecalcs-widget>
Server-side rendering gets widgetMarkup(), which returns the anchor-plus-loader as a string. Single-page apps that inject snippets after navigation can call window.CycleCalcsWidget.scan() for the iframe widgets, or window.CycleCalcsMoon.scan() for the no-iframe moon widget, to mount late arrivals. The scoped alias @cyclecalcs/widget installs the same package.
Recipe 5: roll your own from the API
When a card is too much and you want one sentence in your own typography, call the API from the browser. CORS is open and no key is needed:
<p id="moon-line">Checking the Moon...</p>
<script>
fetch('https://www.cyclecalcs.com/v2/moon')
.then(function (r) { return r.json(); })
.then(function (body) {
document.getElementById('moon-line').textContent =
'Tonight: ' + body.data.phase.name + ', '
+ body.data.phase.illumination_percent + '% lit.';
});
</script>
From there the whole endpoint reference is open to you: sunrise for your courtyard (/v2/sun), the next eclipse with visible-from-here (/v2/eclipses), the best observing night of the next two weeks (/v2/dark-window).
House rules and troubleshooting
- Keep the caption link. The small "by CycleCalcs" anchor under a widget is the entire price of free, and it is also the crawlable fallback when scripts are off.
- Strict CSP? The embed page's troubleshooting section lists the exact directives each widget family needs.
- Privacy: widgets set no cookies and read no storage; a pinned location is baked into your snippet, not detected.