Button and ks:subscribe
The button is the easiest way to turn visitors of your website into subscribers. It needs no API key, only the calendar id.
<div class="ks-subscribe" data-calendar="cal_XXXXXXXXXXXX"></div><script src="https://app.kalender-sync.de/embed/v1/button.js" async></script>Replace cal_XXXXXXXXXXXX with the id of your calendar. Open the demo subscribe page
Attributes
Section titled “Attributes”| Attribute | Effect | Default |
|---|---|---|
data-calendar | Calendar id (cal_ plus 12 characters). Required; without a valid id nothing renders. | |
data-color | Hex color #rrggbb. The button picks the text color itself for enough contrast. | #2563eb |
data-label | Custom button text | “Subscribe to calendar” / “Kalender abonnieren” |
data-lang | de or en | The page’s lang, then the browser language, otherwise English |
You need the script once per page. It renders every element with the class ks-subscribe and a data-calendar.
How the button works
Section titled “How the button works”- It renders into a shadow DOM. Your page’s CSS does not reach in, and its CSS does not leak out.
- It sets no cookies, stores nothing and loads nothing besides the script itself.
- The menu entries are plain links to
https://app.kalender-sync.de/api/public/subscribe/{calendar_id}/go/{app}. Only that request creates the subscription and forwards to the calendar app. Your page sends no JavaScript requests to us, and you need no CORS. - Apps in the menu: Apple Calendar, Google Calendar, Microsoft 365, Outlook.com, Outlook (desktop) and “Other app”, which opens the subscribe page with the feed link. The app that fits the device comes first.
- Escape closes the menu, so does a click outside.
The ks:subscribe event
Section titled “The ks:subscribe event”We don’t track visitors. So that you still know how your button is used, it fires the ks:subscribe event on every click on a menu entry. It bubbles out of the shadow DOM (composed: true), so you can listen on the element or on document.
document.addEventListener('ks:subscribe', (event) => { // event.detail = { calendar: 'cal_XXXXXXXXXXXX', app: 'google' } const { calendar, app } = event.detail;
// Example: forward to your own analytics, under your consent window.plausible?.('Calendar subscribe', { props: { calendar, app } });});app is one of: apple, google, office365, outlook, outlook_desktop, other.
The event runs entirely on your page. Whether and how you use it is up to you, and so is the consent for it.
Pages that render later
Section titled “Pages that render later”Page builders (Elementor, Divi …) and single-page apps (React, Vue …) often insert content after the script ran. Then call this after inserting:
window.KalenderSync?.mountButtons();Buttons that are already rendered stay unchanged. To re-render a button with other attributes, replace the element with a new one and call mountButtons() again.
Example for React:
useEffect(() => { window.KalenderSync?.mountButtons();}, []);
return <div className="ks-subscribe" data-calendar="cal_XXXXXXXXXXXX" />;Your own buttons instead of the script
Section titled “Your own buttons instead of the script”If you don’t want to embed a script, link the calendar’s subscribe_page_url with a button of your own. Subscriptions through the subscribe page are counted the same way.
The subscribe_links from the calendar response work too, but they are not counted in the statistics.
Content Security Policy
Section titled “Content Security Policy”If your website sets a CSP, add to your existing directives:
script-src https://app.kalender-sync.de;style-src 'unsafe-inline';img-src data:;You only need style-src and img-src if your CSP restricts those directives at all: the button brings inline styles in its shadow DOM, and the Microsoft icon is embedded as a data: image. connect-src and frame-src are not needed.