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
type | What the shopper sees | Calls the API? |
|---|---|---|
summary | An 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-snippet | A static "pay in instalments with Qasimha" card for your payment-method list. Learn more opens the popup without the plan table. | No |
faq | A 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
| Item | Requirement |
|---|---|
| Package | @qasimha/widget (version 0.1.0, the version in the CDN URL below) |
| Key | A publishable key: pk_test_... for UAT, pk_live_... for production. Never a secret key. See Authentication. |
| Market | Country SA, currency SAR only |
| Browsers | Chrome / 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.
npm install @qasimha/widgetThe package contains the built bundle dist/qasimha-widget.js and its hash file dist/qasimha-widget.js.sri. Serve the bundle from your own site and load it with the same window.qasimhaWidgetConfig and a <script defer> tag as in the CDN tab. Allow your own origin in script-src. The brand fonts are not in the npm package, so a self-hosted widget uses the system font (see Brand fonts).
Versioned URL or auto-update, not bothVersioned 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:
| Key | Default | Notes |
|---|---|---|
publicKey | none | Required. 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. |
apiBaseUrl | from the key | pk_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.fontSize | inherit | CSS length, e.g. '14px'. |
style.badgeRatio | 1 | Number 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. |
fonts | not set | Set to false to keep your store's font instead of the brand fonts. |
fontsUrl | beside the bundle | Folder holding the brand .woff2 files. |
logoUrl | not set | Reserved 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
| Attribute | Applies to | Notes |
|---|---|---|
type | all | summary (default), card-snippet or faq. An unknown type renders nothing. |
amount | summary | Required. 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-type | summary | Layout, 0 to 6. Default 2. |
lang | all | Overrides the config language for this element. |
title | card-snippet | Replaces the default card title. |
sub-title | card-snippet | Replaces the default card subtitle. |
Changing any of these attributes re-renders the element by itself.
inline-type | Layout |
|---|---|
0 | Your own template (see below). |
1 | Compact one line: wordmark, 4 × [symbol] 300, Learn more. |
2 | Default badge: bordered box, wordmark, summary sentence, trust line, Learn more. |
3 | Wordmark block at the start side, no border. |
4 | Text-only sentence with a Learn more link. |
5 | Two-line card: bold headline with the wordmark, trust line and Learn more below. |
6 | Cart 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")
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-qasimha | Filled with |
|---|---|
instalments | Number of instalments |
plan | Plan phrase, e.g. 4 monthly payments |
instalment-amount | Symbol and instalment amount |
first-instalment-amount | Symbol and first instalment |
total | Symbol and total payable |
fees | Symbol and fees including VAT |
learn-more | Opens 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 testsLanguage 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
langin the config, or per element with thelangattribute. - 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,200and300.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); amountis 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;
amountis below the minimum or above the maximum for your account;typeis unknown.
Failures are not cached. The next refresh() or attribute change tries again.
Content Security Policy
If your site sends a CSP header, allow:
| Directive | Value | When |
|---|---|---|
script-src | https://cdn.qasimha.com | Loading from the Qasimha CDN |
connect-src | https://api.qasimha.com (production, pk_live_ keys) or https://merchant-api-uat.qasimha.com (UAT, pk_test_ keys) | Always, for summary |
font-src | https://cdn.qasimha.com | Only 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
cssconfig 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
localStorageorsessionStorage, 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, nopostMessage, no iframe. Text is set with DOM APIs, neverinnerHTML. - 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
Updated 3 days ago
