Embed widgets
Two drop-in widgets for any blog, docs page, or landing page: a live alternatives table for any SaaS, and a self-host vs SaaS cost calculator.
One <div> + one <script> per widget. Both fetch the os-alt public JSON API at view time, so the freshness, license, and pricing data your readers see is always whatever the index currently shows — no copy-paste rot.
Vanilla JS · zero deps · MIT · CORS-enabled API
1 · Alternatives table
Renders a small table of the top open-source alternatives for one SaaS, with health and license data. ~3KB gzipped.
Copy & paste
<div data-osalt-saas="notion"></div>
<script async src="https://code-rho-dun.vercel.app/embed.js"></script> Replace notion with any slug from the index. The widget renders inline where you put the <div> — no iframe, no popup, no auth.
Live demo
This page is itself an embed host. The block below is rendered by the same /embed.js you'd paste into your site:
Dark theme + 3-row max
<div data-osalt-saas="linear" data-osalt-theme="dark" data-osalt-max="3"></div>
<script async src="https://code-rho-dun.vercel.app/embed.js"></script> Attributes
| Attribute | Required | Values | Default |
|---|---|---|---|
data-osalt-saas | yes | any indexed slug — see /api/saas/index.json | — |
data-osalt-theme | no | light · dark | light |
data-osalt-max | no | integer 1–10 (clamped) | 5 |
2 · Self-host cost calculator
Lets readers pick the SaaS they currently pay for and shows total monthly spend vs a self-hosted stack on a single shared VPS — same logic as /calc/. ~5KB gzipped.
Copy & paste
<div id="osalt-calc"></div>
<script async src="https://code-rho-dun.vercel.app/embed/calc.js"></script> A single mount point per page (id="osalt-calc", or any element with data-osalt-calc). The widget pulls pricing data from /api/saas/index.json at view time.
Live demo
Rendered right here by the same /embed/calc.js you'd paste into your site:
Dark theme
<div id="osalt-calc" data-theme="dark"></div>
<script async src="https://code-rho-dun.vercel.app/embed/calc.js"></script> Attributes
| Attribute | Required | Values | Default |
|---|---|---|---|
id="osalt-calc" or data-osalt-calc | yes | marker on the mount <div> | — |
data-theme | no | light · dark | light |
Footer credit "Powered by osalt.dev/calc/" is mandatory — it's the only thing we ask you not to remove. The link carries a ?ref=embed&host=… tag so we can attribute the embed back to your site.
What the table widget renders
- Header: "Open-source alternatives to {Name}" + category caption.
- Table: project name (links to GitHub), license, setup time, health badge + star count.
- Footer: "View full comparison →" CTA back to the os-alt page (with
?utm_source=embed&utm_medium=widget) + a small "via osalt.dev" credit.
Multiple embeds, same page
Each script auto-scans for its mount points on first load. To re-scan after injecting more divs (single-page apps, comments, modals): call window.osaltEmbed.scan() for the alternatives table, or window.osaltCalc.scan() for the calculator.
Failure modes
- Unknown slug (table widget) → renders a one-line "{slug} is not in the os-alt index yet" with a link back to our homepage. No empty box.
- API down or offline reader → renders a "Network error" / "Could not load calculator data" line, with a fallback link to the full page on osalt.dev.
- Host page CSS hostility → wrappers use
all: initial+ a single class prefix (.osalt-wfor the table,.osalt-cfor the calculator) on every internal element, so inherited styles can't bleed in.
Why no React/Vue package?
The widget is one file you ship via <script>. No bundler, no version pin, no peer dep. Add it to a Hugo blog, a Notion-published page, a Webflow site, or a static README.html with the same line. If you really want to wrap it in a React component, the wrapper is three lines around a useEffect that mounts the div.
Licensing
MIT. Use it on commercial blogs, paywalled docs, sponsored landing pages — we don't care. The CTA back to osalt.dev is the only thing we ask you not to remove (it's how this stays free).