Embeddable widget
The bZapper widget is a standalone component you embed in your own system. Tied to a project, it loads that project's connected numbers and lets your customers manage the connections themselves — connect via QR, disconnect and add a number — plus a mini dashboard of usage and consumption.
It's a way to ship WhatsApp management inside your product without building any UI: one line of code and it's live.
The widget manages the project's connections. Billing (plans and invoices) stays in the panel — the widget never charges or changes a plan.
The runtime always lives at https://widget.bzapper.com.br/v1/widget.js (DigitalOcean CDN).
Don't invent subdomains/paths — copy the exact snippet from the panel under Widgets (it
already includes your key).
How it works, in one sentence
You create a widget key (wgt_…) in the panel, set which origins
(domains) may use it, and paste the script into your site. The widget talks to the
bZapper API with that public key, locked to an origin allowlist (CORS) — your
real API key never reaches the browser.
1. Create the credential in the panel
In the panel, go to Widgets and create a new key:
- Pick the project the widget is tied to (the numbers shown are that project's numbers).
- Configure the origin allowlist: the domains where the widget may run
(e.g.
https://app.yourdomain.com,https://yourdomain.com). Requests from origins outside the list are rejected. - Copy the generated key, in the form
wgt_…. It is public — it can ship in the HTML.
The wgt_ shows up in your site's HTML (unavoidable for a browser widget).
Security doesn't come from hiding the key, but from the origin allowlist: even
with the key in hand, nobody can use it from a domain you didn't authorize.
2. Floating snippet (plug-and-play)
The simplest mode: a bubble in the screen corner that opens the widget with
one click. Paste one line before </body>:
<script
src="https://widget.bzapper.com.br/v1/widget.js"
data-key="YOUR_WGT_KEY"
async
></script>
That's it. The widget injects itself, reads the project's numbers and is available in one click.
3. Embedded snippet (inline)
Want the widget inside a specific area of your page (rather than floating)?
Load the script without data-key and drop the <bzapper-widget> element
wherever you want it to render:
<!-- load the runtime once -->
<script src="https://widget.bzapper.com.br/v1/widget.js" async></script>
<!-- and render the widget wherever you like, like a native block -->
<bzapper-widget data-key="YOUR_WGT_KEY"></bzapper-widget>
The <bzapper-widget> element fills its parent container, like any other block in
your layout.
Attributes
| Attribute | Required | Default | Description |
|---|---|---|---|
data-key | yes | — | The wgt_… key created in the panel under Widgets. |
data-api | no | https://api.bzapper.com.br | API base. Only change it if you use a custom endpoint. |
data-position | no | bottom-right | Floating mode only: bottom-right or bottom-left. |
In floating mode the attributes go on the <script>. In embedded mode they go
on the <bzapper-widget> element.
<!-- floating, bottom-left corner, custom API -->
<script
src="https://widget.bzapper.com.br/v1/widget.js"
data-key="YOUR_WGT_KEY"
data-position="bottom-left"
data-api="https://api.bzapper.com.br"
async
></script>
4. Verify the install
- Open the page where you pasted the snippet and check the browser Network tab: there
should be a
widget.jswith status 200 fromwidget.bzapper.com.br. - In floating mode the bubble shows in the corner. In embedded mode the block renders
inside
<bzapper-widget>. - If you see an origin not allowed error, add the exact domain to the key's allowlist (see Troubleshooting).
If your site uses CSP, allow the widget's script and calls:
script-src https://widget.bzapper.com.br;
connect-src https://api.bzapper.com.br;
In SPAs (React, Vue, Angular, Next…)
The widget is a self-contained Web Component — it works in any framework. In single-page
apps, inject the script once (e.g. in index.html or the root layout) and use the
<bzapper-widget data-key="…"> tag in your JSX/template like any element. In Next.js, load
the script with next/script (strategy="afterInteractive"). The <bzapper-widget> tag won't
clash with your CSS — all of the widget's styling lives in an isolated Shadow DOM.
What the widget does
Tied to the key's project, the widget delivers full connection management:
- List the connected numbers of the project, each with live status (connected, warming, disconnected…).
- Connect via QR — the customer scans the QR and connects a new number right there.
- Disconnect an existing number.
- Add a number — if the project's plan allows more numbers.
- Mini dashboard of usage/consumption for the period: messages, numbers and storage.
All of it without the customer leaving your product, and without you building any screens.
Security
- Origin / CORS. The key only works from the origins you registered in the panel. That's the widget's main access control.
- Public key. The
wgt_ships in the HTML by design and does not expose your real API key. It can only do what the widget needs (manage connections and read the project's usage), and only from allowed origins. - Billing in the panel. Plans and invoices stay in the panel. The widget manages connections — it never charges or changes a plan.
Troubleshooting
The widget doesn't appear / "origin not authorized" error.
The origin (domain) where the widget is running isn't in the key's allowlist. Go
to Widgets in the panel, open the key and add the origin exactly —
including the scheme (https://) and the port if any. Remember that
https://app.example.com and https://example.com are different origins.
It appears, but with no numbers.
Make sure the key is tied to the right project and that the project has
numbers. In embedded mode, check that data-key is on the <bzapper-widget> (not
on the <script>).
I want to point at a different API.
Use data-api. The default is https://api.bzapper.com.br.
Next steps
- Account, projects and users — understand how a project isolates numbers and keys.
- Webhooks — receive connection events
(
instance.connected,instance.disconnected…) in real time on your backend.