Loading the integration script
Every website integration starts with one <script> tag. This page lists the attributes the tag accepts, explains what the script does while it initializes, and shows how to wait for it and how to handle a failed initialization.
TIP
Examples: Attributes - Overview · source — Init Failure Handling · source
Add the script tag
Put this tag in the <head> of every page that opens the editor (or at the end of <body>):
<script
async
src="https://app.trondesigner.com/js/website-integration.js"
referrerpolicy="origin"
data-td-api="https://app.trondesigner.com/api"
data-td-api-key="{API_KEY}"
></script>src— the only public URL of the script. (Older documentation mentions a script URL on theintegration.trondesigner.comhost; that URL doesn't exist.)async— recommended. The script doesn't block rendering, butwindow.tronDesigneronly exists once the script has run (see Wait until the script is ready).referrerpolicy="origin"— recommended. When the browser loads the script it sends only your site's origin, not the full page URL.- Load it as a classic script. Don't use
type="module"and don't bundle the file into your own code: the script reads its configuration from its own<script>element (document.currentScript). - You can also create the tag from JavaScript, for example in a single-page application. Set all
data-td-*attributes before you append the element to the document.
| Environment | src | data-td-api |
|---|---|---|
| Production | https://app.trondesigner.com/js/website-integration.js | https://app.trondesigner.com/api |
| Development | https://app-dev.trondesigner.com/js/website-integration.js | https://app-dev.trondesigner.com/api |
Use a separate API key for each environment. Keys are created in the matching Admin Portal (portal.trondesigner.com / portal-dev.trondesigner.com).
Script tag attributes
The script tag accepts 18 data-td-* attributes. Only the first two are required. Callback attributes take the name of a global function (see Callback functions).
Required
| Attribute | Value |
|---|---|
data-td-api-key | Your website integration API key. |
data-td-api | Script API URL: https://app.trondesigner.com/api. A trailing / is removed. |
Customer — link print jobs to a customer account in your system (details in Customers and orders):
| Attribute | Value |
|---|---|
data-td-customer-identity | Your stable ID of the logged-in customer. When set, the script looks up the TronDesigner customer with this identity (or creates one), so the same customer is recognized on any device. |
data-td-customer-person | Customer's name. Used only together with data-td-customer-identity. |
data-td-customer-company | Customer's company. Used only together with data-td-customer-identity. |
data-td-customer-email | Customer's e-mail. Used only together with data-td-customer-identity. |
Behavior
| Attribute | Value |
|---|---|
data-td-language | Two-letter ISO 639-1 code (for example en, de) of the editor's default UI language. A language the customer picked in the editor earlier takes precedence. Without it, the editor uses the browser language. |
data-td-log-level | debug, info, warn (default) or error. See Debugging and error handling. |
data-td-monitored-element-id | id of an element whose content changes after page load. Action elements added inside it are registered automatically. See HTML data attributes. |
Callbacks — see Events and callbacks for payloads:
| Attribute | Called when |
|---|---|
data-td-script-initialized-callback | Initialization succeeded. No arguments. |
data-td-script-init-failed-callback | Initialization failed. Receives an Error (or a string). |
data-td-print-job-created-callback | A print job was created. |
data-td-print-job-updated-callback | An existing print job was saved. |
data-td-logo-created-callback | A logo was uploaded. |
data-td-logo-updated-callback | A logo was changed. |
data-td-logo-deleted-callback | A logo was deleted. |
data-td-text-created-callback | A text was created. |
data-td-proofreading-created-callback | A proofreading PDF was generated. |
All attributes with formats and examples: Data attributes reference and ScriptElementDataAttributesNames.
Callback functions
The script looks the function up as a property of window by its name. Define it with a function declaration in a classic script, or assign it to window explicitly:
function onTronDesignerReady() { /* … */ } // works
window.onTronDesignerReady = () => { /* … */ }; // works
const onTronDesignerReady = () => { /* … */ }; // doesn't work: not a property of windowFunctions declared inside <script type="module"> aren't global either. If the function isn't found, the script logs Global callback function '…' not found (or … is not a function) to the console.
What happens during initialization
- The script runs and creates
window.tronDesignerright away. At this point you can't open the editor yet. - It waits until the page has fully loaded (
document.readyStateiscomplete, the same moment as the windowloadevent). - It reads the
data-td-*attributes of its<script>element and registers the callback functions. - It initializes the customer by calling the API. The API checks the API key, the license and the page's domain. The customer GUID is stored in the browser's
localStorageunder the keytron-designer-customer, so a returning visitor keeps the same TronDesigner customer. - It loads the editor — the
<trondesigner-editor>web component — from{data-td-api}/resources/trondesigner-editor.js. - It scans the page for elements with
data-td-actionordata-td-optionsand attaches click handlers. It also starts logo visualizations (if your license includes them) and watches the element set indata-td-monitored-element-id. - It reports success: getInitialized() returns
true, the promise from getInitializing() resolves, and thedata-td-script-initialized-callbackfunction is called.
If step 3, 4 or 5 fails — including an editor script that can't be loaded in step 5 (for example a 404, or a Content Security Policy that blocks it) — the script reports the failure instead (see Handle initialization failures) and the editor can't be opened on this page load.
Wait until the script is ready
Pick the option that fits your code:
data-td-script-initialized-callback— simplest; the function runs once, after step 7.getInitializing()— a promise for code that runs later. It resolves after step 7 and rejects when initialization fails, so use it withtry … catch. Because the script isasync,window.tronDesignermay not exist yet when your own inline scripts run; it does exist after the windowloadevent.getInitialized()— a synchronous check, for example at the start of a click handler.
Open the editor only once one of these tells you the script is ready. Called earlier (or after a failed initialization), openDesigner(), open() and the other methods that open the editor log an error and do nothing.
window.addEventListener('load', async () => {
try {
await window.tronDesigner.getInitializing();
// The editor can be opened now.
} catch (error) {
// Initialization failed: hide your design buttons (see below)
console.error('TronDesigner is unavailable:', error?.cause ?? error?.message ?? error);
}
});
function onDesignClick() {
if (!window.tronDesigner?.getInitialized()) return; // not ready yet, or initialization failed
window.tronDesigner
.setExactProduct('PFC', undefined, (product) => product.addVariant('10086021'))
.addExactPrinting('front', 'PAD03')
.open({ mode: 'dialog' });
}An exception thrown inside your data-td-script-initialized-callback is logged to the console and doesn't change the result of getInitializing().
Handle initialization failures
Initialization fails when the API rejects the request (wrong key, domain not allowed, license), when data-td-api-key / data-td-api is missing, when the browser has no localStorage, or when the editor script can't be loaded (404, blocked by a Content Security Policy). The script then:
- rejects the getInitializing() promise with the error (if nobody waits for the promise, this doesn't produce an "unhandled rejection" error),
- calls the function named in
data-td-script-init-failed-callbackwith the error (an exception inside that function is logged and changes nothing), and - dispatches a
userInitFailedCustomEventon its own<script>element, with the error inevent.detail. The event doesn't bubble, so listen on the script element itself.
Use whichever fits your code; all three get the same error.
<script
async
src="https://app.trondesigner.com/js/website-integration.js"
referrerpolicy="origin"
data-td-api="https://app.trondesigner.com/api"
data-td-api-key="{API_KEY}"
data-td-script-init-failed-callback="onTronDesignerInitFailed"
></script>
<script>
function onTronDesignerInitFailed(error) {
// error.cause holds the server's reason, e.g. "API key is invalid: Domain shop.example.com is not allowed"
console.error('TronDesigner is unavailable:', error?.cause ?? error?.message ?? error);
document.querySelectorAll('.design-button').forEach((button) => (button.hidden = true));
}
</script><script
async
id="trondesigner-script"
src="https://app.trondesigner.com/js/website-integration.js"
referrerpolicy="origin"
data-td-api="https://app.trondesigner.com/api"
data-td-api-key="{API_KEY}"
></script>
<script>
document.getElementById('trondesigner-script').addEventListener('userInitFailed', (event) => {
const error = event.detail;
console.error('TronDesigner is unavailable:', error?.cause ?? error?.message ?? error);
});
</script>When the API rejects the request, the error message is ApiCaller::call: failed - response status 401 and error.cause contains the reason:
error.cause | What to do |
|---|---|
API key is invalid: Provided API key is not valid | Check data-td-api-key. |
API key is invalid: API key is disabled | Enable the key in Settings → API Keys. |
API key is invalid: Domain … is not allowed | Add the page's host name to the key's allowed domains. |
API key is invalid: Web Integration feature for TronDesigner license is required for integrations outside of PromoTron platform! | Your license needs the Web Integration feature. |
API key is invalid: TronDesigner instance is not active / … is expired | Contact PromoTron support. |
API key is invalid: Missing referer in header | The browser sent neither a Referer nor an Origin header. |
If data-td-api-key or data-td-api is missing, the console shows initialization failed - cannot receive API key (or API url) and the callback receives an error with that message. If the editor script can't be loaded, the error message is initialize: cannot load the editor (…/resources/trondesigner-editor.js).
Allowed domains
Each website integration API key has a list of allowed domains (Admin Portal → Settings → API Keys → Website Integration API Keys). The API takes the host name from the Referer header of each request (or from Origin when there is no Referer) and accepts the request when the host name is one of the entries or a subdomain of one.
- Enter host names only:
shop.example.com,example.com,localhost. Nohttps://, port or path. example.comalso matchesshop.example.comandwww.example.com, but notmyexample.com.- Ports are ignored:
localhostcovershttp://localhost:3000andhttp://localhost:8080. - Pages opened from disk (
file://) have no host name and are always rejected.
The key is visible in your page source; allowed domains are what stop other sites from using it. Never put a REST API key in a web page.
WARNING
Don't leave localhost on a production key. Every browser can open a page on localhost, so a key that allows it can be used by anyone who copies it from your page source — on your license, creating logos and print jobs in your instance. Use a separate key for development and testing (with localhost, a staging domain, …) and keep only your live domains on the production key. Remove localhost once the integration is finished.
For the same reason, don't allow shared hosting domains such as csb.app, vercel.app or netlify.app: anyone can publish a site under them. Allow your exact subdomain instead (my-shop.vercel.app).
Content Security Policy
If your site sends a Content-Security-Policy header, allow at least:
script-src https://app.trondesigner.com— the integration script and the editor module,connect-src https://app.trondesigner.com— API requests,style-src https://app.trondesigner.com 'unsafe-inline'— the editor's stylesheets, and a small<style>element the script adds to<head>,font-src https://app.trondesigner.com— the editor's icon font,- the host of your
ownCssVariablesUrlinstyle-src, if you use it (see Styling the editor).
The editor also loads images and other assets while it runs. Test with the browser console open and add any hosts it reports as blocked.
See also
- getInitializing · getInitialized — API reference
- ScriptElementDataAttributesNames — attribute constants
- Quick start
- Data attributes reference
- Debugging and error handling