Skip to content

Custom widgets overview ​

A custom widget is a small front-end app you package as a ZIP and upload to Bito. You can run it privately in your own account, or publish it after both its executable release and marketplace card pass moderation. Bito serves the approved files and loads them into the admin panel, where your code renders inside the product's own screens: a tab on a customer profile, an entry in a phone-number menu, an always-on background widget, or its own settings page.

If you have written an amoCRM widget, the shape will be familiar: script.js is an AMD module that returns a CustomWidget constructor with a callbacks object, and it is handed jQuery 4 as $.

A widget is not sandboxed. At all.

Your script.js is loaded with a plain <script src> and executes in the admin panel's own origin and session. It can call any admin endpoint as the signed-in user, read the DOM of every screen, and reach the browser storage of the ERP. There is no iframe, no sandbox attribute, no per-widget CSP, and no permission system narrowing what it may touch.

The control is the tenant's per-release consent screen, not isolation. A tenant installing your widget is trusting you — the developer — with everything the signed-in user can do, including trade, finance and payroll data. Bito reviews submissions; it does not guarantee third-party code.

This replaces the older iframe widget, where your own hosted page was embedded in an iframe on the integration's settings tab. That mechanism still exists for Bito's own built-in integrations (iframe.url plus a one-time token), but it is not how a custom widget works.

The shape of it ​

text
  Developer                        Bito                          Tenant
      |                              |                              |
      |  1. Build widget.zip         |                              |
      |  2. Complete the app card,   |                              |
      |     create a release,        |                              |
      |     upload the archive       |                              |
      |----------------------------->|                              |
      |     validation report        |                              |
      |<-----------------------------|                              |
      |  3. Test locally, then       |                              |
      |     submit release review    |                              |
      |----------------------------->|                              |
      |                              |  4. Release moderation       |
      |                              |     approve -> assets        |
      |                              |     extracted + runnable     |
      |  5. Submit card review       |                              |
      |<-----------------------------|                              |
      |                              |  6. Card approval -> public  |
      |                              |  7. Tenant installs          |
      |                              |<-----------------------------|
      |                              |  8. Boss accepts the         |
      |                              |     consent for THIS release |
      |                              |<-----------------------------|
      |                              |  9. mount -> script.js runs  |
      |                              |     in the admin panel       |

Where the files are served from ​

Approved assets are extracted and served from a separate registrable domain, not a bito.uz subdomain. That buys cookie isolation and a smaller cache blast radius — it does not sandbox anything. A cross-origin <script src> still executes in the page that loaded it, which is the entire point of this model.

Files are served with X-Content-Type-Options: nosniff and a content type assigned server-side from the extension allowlist, never from anything you send.

A tenant's acceptance is bound to the exact release they accepted. Publishing a new approved version re-prompts every tenant, because the code being trusted has changed. Until the prompt is accepted, mount refuses and your widget does not run.

Only a boss or additional boss can accept — an ordinary employee sees who must. Acceptance records who accepted and when, and the tenant can revoke it, which unmounts the widget everywhere.

What a widget is made of ​

FileRequiredPurpose
manifest.jsonYesInterface version, declared languages, mount surfaces, disclosed destinations
script.jsYesThe AMD module returning your CustomWidget
i18n/<lang>.jsonOne per declared languageFlat key → string bundle, resolved server-side
style.cssNoInjected into the host document as a <link>
templates/NoNamed templates for bito.render()
images/NoStatic assets

Full rules and limits: the widget.zip format.

PageWhat it answers
The widget.zip formatWhat goes in the archive and what gets it rejected
The CustomWidget lifecycleWhich callbacks run, in what order, and what happens when one throws
The bito SDKEvery method on window.bito
Mount surfacesWhere in the product your widget can appear
jQuery compatibilityWhat is replaced in the bundled jQuery 4
Publishing a releaseVersions, the review queue, what approval changes
Your app pageThe separate marketplace-card and release workflows
Becoming a Bito developerHow to get an account that can do any of this

Bito 2.0 Integration API