Install the on-site widget

Show Qasimha instalment plans, a payment-method card and an FAQ on your product, cart and checkout pages with one script.

@qasimha/widget adds a <qasimha-widget> element to your pages. It shows the shopper what they would pay in instalments, before they reach checkout. It is one script with no dependencies. It draws inside Shadow DOM (an isolated part of the page), so your CSS and the widget's CSS do not mix.

The widget only displays plans. It does not start a checkout. To take payment, create a checkout session on your server (see Checkout flows).

What it shows

typeWhat the shopper seesCalls the API?
summaryAn instalment line or badge for a price, e.g. "4 monthly payments of [symbol] 300", with a Learn more link that opens a plan popup. Seven layouts (see inline-type below), including a benefits tile for the cart.Yes
card-snippetA static "pay in instalments with Qasimha" card for your payment-method list. Learn more opens the popup without the plan table.No
faqA six-question FAQ accordion.No

The popup shows the plans offered for the amount, the schedule of the selected plan (due dates, amounts, fees, total), "How it works?" and "Why Qasimha?".

Requirements

ItemRequirement
Package@qasimha/widget (version 0.1.0, the version in the CDN URL below)
KeyA publishable key: pk_test_... for UAT, pk_live_... for production. Never a secret key. See Authentication.
MarketCountry SA, currency SAR only
BrowsersChrome / Edge 79+, Firefox 63+, Safari 12.1+

Load the widget

Set the configuration first, then load the script. Pick one way to load it.

<script>
  window.qasimhaWidgetConfig = {
    publicKey: 'pk_test_...', // required
    lang: 'ar',               // 'ar' (default) or 'en'
    country: 'SA'             // only SA is supported
  };
</script>
<script defer
        src="https://cdn.qasimha.com/widget/0.1.0/qasimha-widget.js"
        integrity="sha384-..."
        crossorigin="anonymous"></script>

Each release ships its integrity value beside the bundle, in a file named qasimha-widget.js.sri. Copy that value into the integrity attribute.

Versioned URL or auto-update, not both

Versioned URLs (/widget/<version>/) never change, so you can pin them with SRI (Subresource Integrity: the browser refuses the file if its hash differs). The /widget/v1/ channel updates itself, so it cannot carry an SRI hash. Choose one. A versioned URL with SRI is the safer option.

Then place elements where you want them:

<qasimha-widget type="summary" amount="1200" inline-type="2"></qasimha-widget>
<qasimha-widget type="card-snippet"></qasimha-widget>
<qasimha-widget type="faq"></qasimha-widget>

If you use React or Angular, the Web SDKs can load and configure the widget for you.

Configuration

window.qasimhaWidgetConfig keys:

KeyDefaultNotes
publicKeynoneRequired. Must match pk_test_... or pk_live_.... Otherwise nothing renders and one console.warn is logged.
lang'ar''ar' or 'en'. Unknown values fall back to 'ar'.
country'SA'Any other value renders nothing.
apiBaseUrlfrom the keypk_live_ uses production, pk_test_ uses UAT. Must be https; http only for localhost / 127.0.0.1.
css''Extra CSS added inside the shadow root. Targets the .qw-* classes.
style.fontSizeinheritCSS length, e.g. '14px'.
style.badgeRatio1Number from 0.5 to 3. Scales the badge text.
style.borderRadius'10px'Corner radius of badges and cards.
style.primaryColor'#fd6c43'Qasimha coral. Used for the selected plan, focus rings and icons.
fontsnot setSet to false to keep your store's font instead of the brand fonts.
fontsUrlbeside the bundleFolder holding the brand .woff2 files.
logoUrlnot setReserved for a wordmark image. Until a logo asset exists, the wordmark is plain text.

Every value is checked. A bad style value is ignored. A bad publicKey, country or apiBaseUrl stops rendering.

Element attributes

AttributeApplies toNotes
typeallsummary (default), card-snippet or faq. An unknown type renders nothing.
amountsummaryRequired. Plain decimal with up to 9 digits and up to 2 decimals, e.g. 1200 or 300.50. No currency sign, no thousands separator. Anything else, or zero, renders nothing.
inline-typesummaryLayout, 0 to 6. Default 2.
langallOverrides the config language for this element.
titlecard-snippetReplaces the default card title.
sub-titlecard-snippetReplaces the default card subtitle.

Changing any of these attributes re-renders the element by itself.

inline-typeLayout
0Your own template (see below).
1Compact one line: wordmark, 4 × [symbol] 300, Learn more.
2Default badge: bordered box, wordmark, summary sentence, trust line, Learn more.
3Wordmark block at the start side, no border.
4Text-only sentence with a Learn more link.
5Two-line card: bold headline with the wordmark, trust line and Learn more below.
6Cart benefits tile: logo on top, "Pay in 4 payments of [symbol] 300" below. The whole tile opens the popup.

The headline plan is the first plan the API returns. Qasimha decides the order.

Your own template (inline-type="0")

Write your own markup inside the element. Mark the nodes the widget should fill with data-qasimha:

<qasimha-widget type="summary" amount="1200" inline-type="0">
  أو <span data-qasimha="instalments"></span> دفعات ×
  <span data-qasimha="instalment-amount"></span>
  <button type="button" data-qasimha="learn-more">المزيد</button>
</qasimha-widget>
data-qasimhaFilled with
instalmentsNumber of instalments
planPlan phrase, e.g. 4 monthly payments
instalment-amountSymbol and instalment amount
first-instalment-amountSymbol and first instalment
totalSymbol and total payable
feesSymbol and fees including VAT
learn-moreOpens the popup on click

When there are no plans, the whole element is hidden, so your template never shows without numbers.

Prices that change on the page

On a single-page store, when the price changes, either update the amount attribute or call the refresh function:

window.QasimhaWidget.refresh();   // Promise<void>: re-reads the config, re-renders every element
window.QasimhaWidget.version;     // '0.1.0'
document.querySelector('qasimha-widget').whenRendered(); // Promise<void>, useful in tests

Language and right-to-left

  • Arabic is the default and renders right-to-left; English renders left-to-right.
  • Set the language for the page with lang in the config, or per element with the lang attribute.
  • Amounts always use the Saudi riyal symbol to the left of the number, in a left-to-right span, in both languages. Digits are Latin, with a thousands separator, e.g. 1,200 and 300.50.

Where the numbers come from

The summary type reads plans from the plans endpoint with your publishable key. That endpoint is documented in Plans widget API. The widget keeps each answer in memory for the life of the page, and ten badges for the same price make one request.

The widget fails closed: it shows nothing, never a guessed or computed number, when:

  • the config is invalid (publicKey, country, apiBaseUrl);
  • amount is malformed or zero;
  • the request fails, times out (5 seconds) or returns a non-2xx status;
  • the response is not a success, the currency is not SAR, or there are no plans;
  • amount is below the minimum or above the maximum for your account;
  • type is unknown.

Failures are not cached. The next refresh() or attribute change tries again.

Content Security Policy

If your site sends a CSP header, allow:

DirectiveValueWhen
script-srchttps://cdn.qasimha.comLoading from the Qasimha CDN
connect-srchttps://api.qasimha.com (production, pk_live_ keys) or https://merchant-api-uat.qasimha.com (UAT, pk_test_ keys)Always, for summary
font-srchttps://cdn.qasimha.comOnly when the brand fonts are hosted there
style-src'unsafe-inline'Only if you must support browsers without constructable stylesheets

Modern browsers get the widget styles through adoptedStyleSheets and need no style-src change.

Brand fonts

The widget can use Qasimha's Outreque (Latin) and Zanjabeel (Arabic) fonts. It registers them under its own names, so your store's fonts are never replaced. It looks for them in fonts/ beside the bundle, or in fontsUrl. If they are not there, it uses the system font and nothing else changes. Set fonts: false to always use your store's font.

Styling

  • CSS custom properties on the element: --qw-primary, --qw-on-primary, --qw-text, --qw-muted, --qw-border, --qw-bg, --qw-surface, --qw-radius, --qw-font-size, --qw-scale.
  • For deeper changes, pass CSS in the css config key. It can target classes such as .qw-badge, .qw-pill, .qw-link, .qw-money, .qw-faq, .qw-dialog.

What the widget never does

  • No cookies, no localStorage or sessionStorage, no tracking.
  • No third-party requests. It only calls the Qasimha plans endpoint and, if hosted, the font files.
  • No eval, no inline event handlers, no postMessage, no iframe. Text is set with DOM APIs, never innerHTML.
  • No invented numbers. No plans from the API means nothing on screen.
  • No card data and no shopper data. It holds only your publishable key, so embedding it keeps you in PCI DSS SAQ-A scope.

Troubleshooting

Nothing appears on the page

Open the browser console. A console.warn means the publicKey is missing or malformed. Then check that country is SA, that amount is a plain decimal such as 1200.00 (no commas, no currency), and that the amount is inside your account's minimum and maximum. Low prices may simply be below the minimum.

The console shows a CSP error

Add the CDN host to script-src and the API host for your environment to connect-src. See Content Security Policy.

The script is blocked with an integrity error

The integrity value does not match the file. Use the value from the qasimha-widget.js.sri file of the same version as the URL. Do not use SRI with the /widget/v1/ channel.

The badge keeps the old price after a change

Update the amount attribute on the element, or call window.QasimhaWidget.refresh() after you change the config.

The popup is cut off or in the wrong place

The popup uses position: fixed. If a parent element has transform, filter or contain set, the popup is positioned inside that parent. Move the widget outside such elements.

Test keys show no plans

A pk_test_ key talks to UAT and a pk_live_ key to production. Make sure the key belongs to the environment you expect and that connect-src allows that host.

Next steps


Did this page help you?