← Guides

Add a live MRR calendar widget to your website

Embed a live revenue contribution graph on a landing page, pricing page, blog, or footer—with one small script and a no-JavaScript image fallback.

Last updated July 10, 2026

What the widget shows

The MRR Calendar widget is a small, live slice of your revenue calendar. It combines a headline metric with a contribution-style graph, so a visitor can see both the current result and the rhythm behind it.

The graph always represents daily revenue activity. The headline can show MRR, revenue over the past 30 days, active subscriptions, a revenue streak, or paid days this year. This distinction is explicit in the widget: an active-subscriptions headline is never mislabeled as subscription activity when the grid is showing revenue.

The widget refreshes from your published MRR Calendar data. It does not expose your Stripe keys or private project data.

Choose the right format

  • Calendar card — the strongest visual signature. Use it in a landing-page section, an About page, or beside customer proof.
  • Proof badge — a compact metric and seven-day activity pulse. Use it near a call to action or in a footer.
  • Activity strip — a wider, lower profile view with up to six months of activity. Use it in a pricing page, changelog, or blog layout.

All three formats are responsive to their container, inherit your MRR Calendar accent color by default, and support light, dark, or automatic theme selection.

Install in four steps

Step 1 — In MRR Calendar, open Share → Widget and choose a format.

Step 2 — Choose the metric, privacy level, theme, accent, and intended placement. If you have several projects, select which ones can contribute public data.

Step 3 — Publish the widget. The installation panel generates the code for your widget; the example below uses placeholders and will not work until replaced with the generated values.

<mrr-calendar-widget data-widget="YOUR_WIDGET_TOKEN">
  <a href="YOUR_PUBLIC_PAGE_URL">View the live revenue calendar</a>
</mrr-calendar-widget>
<script async src="https://mrrcalendar.com/widget.js"></script>

Step 4 — Paste the code where the widget should appear and visit the page. A valid installation appears in the configurator after the widget has been at least 50% visible for one second.

HTML and static sites

Paste the generated custom element and script before the closing </body> tag, or directly inside the content block where the widget belongs. The script can be loaded once even when the page contains several widget elements.

Keep the fallback link inside <mrr-calendar-widget>. It gives visitors a useful link before JavaScript runs and keeps the public-page destination present in the document HTML.

Next.js

Render the generated custom-element markup in a Client or Server Component, then load the script with next/script. Use strategy="afterInteractive"; the widget does not need to block the first render.

import Script from 'next/script';

export function RevenueWidget() {
  return (
    <>
      <div
        dangerouslySetInnerHTML={{
          __html:
            '<mrr-calendar-widget data-widget="YOUR_WIDGET_TOKEN"></mrr-calendar-widget>',
        }}
      />
      <Script src="https://mrrcalendar.com/widget.js" strategy="afterInteractive" />
    </>
  );
}

The configurator generates this wrapper with your real widget ID and fallback link, so TypeScript does not need a global JSX declaration for the custom element.

Framer, Webflow, WordPress

In Framer, use an Embed component. In Webflow, use a Code Embed element. In WordPress, use a Custom HTML block. Paste the complete generated snippet without moving the script into a rich-text field that strips scripts.

When a platform or security plugin removes custom scripts, use the no-JavaScript image instead.

No-JavaScript image

Every published widget has an SVG endpoint. The configurator generates an <img> snippet that works in email-like builders, strict CMS environments, and documentation pages.

The image does not collect impressions or clicks. Wrap it in the generated public-page link if you want the image to be interactive.

The widget and public page are independent publishing controls. You can publish the widget while the public page is disabled; the widget then renders as a non-clickable information surface.

When you enable the public page later, the JavaScript widget becomes clickable automatically without reinstalling it. The destination includes stable utm_source=widget attribution and never includes the private widget token.

Analytics and privacy

Widget analytics are optional. When enabled, an impression requires at least 50% visibility for one second while the document is visible. A click is recorded only for a linked widget.

The widget writes no cookie or localStorage. MRR Calendar uses an ephemeral, widget-specific daily fingerprint to estimate unique impressions. It does not create a reusable visitor identity across widgets or sites, and it never stores a raw IP address or raw user agent in the analytics event.

Analytics reports keep public-page views and widget impressions separate. Their daily-unique figures are not added into a misleading global visitor total.

Content Security Policy

Sites with a strict Content Security Policy must allow:

  • https://mrrcalendar.com in script-src for the loader;
  • https://mrrcalendar.com in connect-src for widget data and optional analytics events;
  • inline styles inside the widget's Shadow DOM, or a compatible style-src rule.

The widget does not load fonts, images, trackers, or third-party frameworks.

Troubleshooting

If the widget shows “unavailable,” first check that it is published and that the page origin is included in the optional origin allowlist. Origins must include the protocol and hostname, for example https://example.com, without a path.

If the design appears but verification stays empty, scroll until at least half of the widget is visible and keep the tab active for one second. Also confirm that widget analytics are enabled.

If the widget is not clickable, enable your public page in Share → Public page. The widget continues to display when the public page is disabled; only its destination is removed.