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

More build guides