# QuietJar for developers - One script tag, no layout shift

For developers
# A support button for your docs site.

One script tag. No layout shift. Give it a goal and it hides once the goal is met. Fully configurable.

## Install

```
<script>
  window.QuietJar = {
    "site": "qj_your_site_id",
    "currency": "eur",
    "amounts": [3, 5, 10],
    "labels": {
      "headline": "Support this site",
      "body": "Enjoying the docs? Buy us a coffee.",
      "action": "Tip"
    },
    "style": { "color": "#0369a1", "font": "rounded" },
    "close": { "enabled": true, "after": "session" },
    "position": { "corner": "bottom-right" }
  };
</script>
<script src="https://quietjar.com/js/latest/quietjar.js" async></script>
```

1. 01Copy the snippet and paste it into your page's HTML.
1. 02Fill in your site id from the dashboard. If you are logged in on this site, it is already filled in.
1. 03Adjust the settings below. Every one of them has a default, so the snippet works as pasted.

Plain HTML shown here. Astro, Hugo, Docusaurus, and VitePress work the same way: the snippet goes in the layout or in the page.

## Settings reference

The widget reads its settings from a window.QuietJar object on the page, before the script tag loads. Every setting has a default; site is the only one with a visible consequence when it is missing.

|  | Type | Required | Default | What it does |
| --- | --- | --- | --- | --- |
| site | string | yes | — | Your public site key from the dashboard. Without it the widget renders, but the checkout cannot take payments. |
| currency | string | no | eur | ISO 4217 three-letter code, case-insensitive. The bounds and preset amounts follow the currency. An unknown code falls back to eur. |
| goal | string | no | — | A goal id from the dashboard. When set, the card renders a progress meter for it. |
| goalReached | string | no | hide | What the widget does once the goal is reached. Ignored without a goal. Anything else falls back to hide.
hideThe widget stops rendering, so the page no longer asks.showThe widget stays and keeps taking donations, without the bar.show-with-barThe widget stays and keeps the filled bar. |
| amounts | number[] | no | per-currency presets | Amounts offered in the checkout, in major units. At most 4 are kept, deduplicated and sorted. Entries that are not finite numbers or sit outside the currency's bounds are dropped; if none survive, the presets are used. |
| labels.headline | string | no | — | The button label. When unset, the widget renders as an icon-only pill whose accessible name falls back to "Support this site". |
| labels.body | string | no | — | The card body. When set, the widget renders as a card with a headline and an action button instead of a pill button. |
| labels.icon | string | no | piggy | The icon on the button: any text glyph, or piggy for the pig mark. An empty string removes the icon. A value longer than 8 characters falls back to the default. |
| labels.action | string | no | Support | The card's action button label. |
| labels.close | string | no | Dismiss | The accessible name of the close control. |
| labels.thanks | string | no | Thank you for your support | Shown in the checkout once a tip succeeds. |
| labels.other | string | no | Other | The label of the free-entry amount option. |
| labels.minimize | string | no | Minimize | The accessible name of the control that collapses the checkout. |
| style.color | string | no | #0369a1 | The accent color as a hex value: #rgb, #rgba, #rrggbb or #rrggbbaa. Anything else falls back to the default. |
| style.font | string | no | rounded | The font stack the widget uses. Anything else falls back to rounded.
systemThe platform's own UI font, such as San Francisco or Segoe UI.serifA system serif, such as Georgia or Charter.roundedA rounded system font, such as SF Pro Rounded. Falls back to the system font where none is installed.monoA system monospace font, such as SF Mono or Cascadia Mono.inheritThe page's own font stack. |
| style.css | string | no | — | Raw CSS appended after the widget's own stylesheet, for overrides the settings above cannot express. |
| close.enabled | boolean | no | true | Whether the close control visitors can use to dismiss the widget is shown. |
| close.after | string | no | session | What a visitor closing the widget does to its visibility. Anything else falls back to session.
sessionHidden until the next visit.daysHidden for close.days.neverReappears on the next page load.foreverNever shown again. |
| close.days | number | no | 7 | Days hidden after closing. Only used when close.after is days. A whole number of one or more; anything else falls back to 7. |
| donation.hideDays | number | no | 30 | Days hidden after a completed donation, so the widget does not ask again right away. Same whole-number rule as close.days. |
| position.corner | string | no | bottom-right | Where the widget floats. Anything else falls back to bottom-right.
bottom-rightBottom right corner of the viewport.bottom-centerBottom center of the viewport.bottom-leftBottom left corner of the viewport.top-rightTop right corner of the viewport.top-centerTop center of the viewport.top-leftTop left corner of the viewport. |
| mount.target | string or HTMLElement | no | — | A CSS selector or element the widget mounts into, inside the page's flow, instead of floating in the fixed corner. Invalid or missing falls back to the corner. |

Logged in on this site? Your own site id is filled into the snippet above. Your personalized snippet is also on the widget page in the dashboard.

### Examples
amountsamounts: [3, 5, 10] offers three preset buttons in the checkout, shown in the site's currency.close.afterclose.after: "days" with close.days: 7 hides the widget for a week after a visitor dismisses it.labels.iconlabels.icon: "☕" puts a coffee cup on the button. labels.icon: "" removes the icon entirely.position.cornerposition.corner: "bottom-center" floats the widget at the bottom center of the viewport.mount.targetmount.target: "#donate-slot" places the widget inline inside that element instead of the floating corner.
### Invalid and missing values

Nothing fails loudly. Every setting falls back to the default listed above when it is missing or invalid, and unusable amounts entries are dropped rather than shown. The only value with visible consequences when missing is site: the widget renders, but the checkout cannot take payments.

## Performance

Script size: 38.6 kB (11.7 kB gzipped over the wire). Load time: around 40 ms on a cold cache. The button floats in a fixed corner layer, so it displaces nothing on your page: zero layout shift. Stripe's payment code loads only when someone opens the checkout, not on page load.

## How it steps back

After a successful payment, the button enters a quiet state for a while and shows a thank-you instead of asking again. The record lives in the visitor's browser, so nothing is stored on our side and there is no server-side suppression. You pick how long it steps back in the dashboard: 30 days by default. Safari clears browser storage after 7 days without a visit, so a long step-back can end early there. Internally we call it suppression.

## Payment methods
Apple PayAppears on iPhone, iPad, and Mac. One tap with Face ID.Google PayAppears in Chrome and on Android. One tap, no forms.CardsVisa, Mastercard, Amex, Cartes Bancaires. The fallback that always works.LinkStripe's own wallet. Returning supporters pay without retyping a card.iDEALFor visitors with a Dutch bank. They pay in their own banking app.Local methodsBancontact, EPS, Revolut Pay, BLIK, Satispay, Pay by Bank, where available.
## Goals

Give the button a public target and a bar that fills toward it: hosting for the year, the next release, a new microphone. Concrete goals lift the amounts people choose. Set one in the dashboard next to the button's style.

## Open the panel from your own code

Wire the checkout to your own call to action: the end of an article, a finished download, a tag manager. Call window.QuietJar.open() anywhere on the page and the panel opens right there. It sits next to the widget when that is visible, and centers on the page when it is not. The call always opens, even for visitors the widget stepped back for.
[QuietJar vs Ko-fi](/en/compare/ko-fi/)[QuietJar vs Buy Me a Coffee](/en/compare/buymeacoffee/)