Widget Embedding Guide

Add the chat assistant to your store with a single line of code

Overview

The Emporiqa chat widget is a lightweight chat assistant that you can embed on your e-commerce store. It provides:

  • 24/7 customer support
  • Product search and recommendations
  • Optional order tracking (if configured in store settings)
  • Multi-language support
  • Responsive design (works on desktop and mobile)
  • Customizable appearance to match your brand
  • Optional human handoff for complex queries

One line of code: The widget is embedded with a single script tag. No complex setup or build process required.

Platform Support: We have ready-to-use integrations for Drupal Commerce, WooCommerce, Sylius, Magento 2, PrestaShop, and Shopware. The widget works with any website or e-commerce platform.

Getting Your Store ID

Each store has a unique Store ID that identifies it. To find your Store ID and embed code:

  1. Log in to your Emporiqa dashboard
  2. Navigate to Store SettingsStore Integration tab
  3. Find your Store ID in the header and the ready-to-use Embed Code in the Chat Widget Integration section
  4. Click the copy button to copy either the Store ID or the complete embed code

Quick Tip: The embed code is ready to use - just copy and paste it into your store's HTML.

Important: Before embedding the widget, ensure you have sent your product and page data via webhooks. The widget won't function properly without product data.

Basic Embedding

Add this single line of code to your website, just before the closing </body> tag:

<script async crossorigin="anonymous" src="https://emporiqa.com/chat/embed/?store_id=YOUR_STORE_ID&language=en"></script>

Replace YOUR_STORE_ID with your actual Store ID, and en with your store's language code (e.g., en, de, fr, pt-br, zh-cn). Both 2-letter codes and full regional codes are accepted. Codes are case-insensitive: EN, en-US, and en-us all work.

Cross-language support: The language parameter sets the language of your store content (products, pages). If a customer writes in a different language, the salesperson automatically detects it and responds in their language while searching your content in its original language.

Required Parameters: Both store_id and language are required. The widget will not load without them.

Optional Parameters

You can add optional parameters to control currency display and sales channel filtering:

<script async crossorigin="anonymous" src="https://emporiqa.com/chat/embed/?store_id=YOUR_STORE_ID&language=en&currency=EUR&channel=b2b"></script>
Parameter Required Description
store_id Yes Your store's unique identifier
language Yes Language code for the widget (e.g., en, de, pt-br). Determines the display language and which product translations to search.
currency No ISO 4217 currency code (e.g., EUR, USD). When set, product prices are shown in this currency. Products without a matching price entry use the first available price as fallback.
channel No Sales channel identifier (e.g., b2b, retail). When set, only shows products and pages from this channel plus store-wide items.
user_id No HMAC-signed customer token for order tracking. See User Identification.

Example

<!DOCTYPE html>
<html>
<head>
    <title>My Store</title>
</head>
<body>
    <!-- Your store content -->

    <!-- Emporiqa Widget - place before </body> -->
    <script async crossorigin="anonymous" src="https://emporiqa.com/chat/embed/?store_id=ABC123xyz...&language=en"></script>
</body>
</html>

The script automatically creates a floating chat button in the corner of your page. Customers can click it to open the chat widget.

User Identification

You can optionally pass a user_id parameter to track conversations across sessions and devices. This is useful for logged-in customers. If you use order tracking, the user ID is forwarded to your order tracking API so you can restrict results to that customer's orders.

The user_id parameter must be a signed token generated server-side using your connection secret. This prevents customers from forging another user's identity.

Token Format

The token is composed of two parts separated by a dot: a Base64url-encoded JSON payload and an HMAC-SHA256 signature.

base64url({"uid":"CUSTOMER_ID","ts":UNIX_TIMESTAMP}).hmac_sha256_hex(payload, webhook_secret)
  • uid - Any string that uniquely identifies the customer (customer ID, email, account number)
  • ts - Unix timestamp when the token was created. Tokens expire after 90 days.

Generating the Token (Server-Side)

The token must be generated on your server - never expose the connection secret to the browser.

PHP

function emporiqa_generate_user_token(string $userId, string $webhookSecret): string
{
    $payload = json_encode(['uid' => $userId, 'ts' => time()], JSON_UNESCAPED_SLASHES);
    $encodedPayload = rtrim(strtr(base64_encode($payload), '+/', '-_'), '=');
    $signature = hash_hmac('sha256', $encodedPayload, $webhookSecret);

    return $encodedPayload . '.' . $signature;
}

Python

import base64, hashlib, hmac, json, time

def emporiqa_generate_user_token(user_id: str, webhook_secret: str) -> str:
    payload = json.dumps({"uid": user_id, "ts": int(time.time())}, separators=(",", ":")).encode()
    encoded_payload = base64.urlsafe_b64encode(payload).decode().rstrip("=")
    signature = hmac.new(webhook_secret.encode(), encoded_payload.encode(), hashlib.sha256).hexdigest()
    return f"{encoded_payload}.{signature}"

Embedding with the Token

<script async crossorigin="anonymous" src="https://emporiqa.com/chat/embed/?store_id=YOUR_STORE_ID&language=en&user_id=TOKEN_HERE"></script>

Drupal Commerce (PHP)

$params = ['store_id' => $store_id, 'language' => $language];
if ($user->isAuthenticated()) {
    $params['user_id'] = emporiqa_generate_user_token((string) $user->id(), $webhook_secret);
}
$url = 'https://emporiqa.com/chat/embed/?' . http_build_query($params);

Important: Never expose your connection secret in client-side code. The token must be generated on the server and injected into the page template.

Tip: If you don't need user identification, simply omit the user_id parameter. The chat widget works without it. The customer's user ID will not be available for order tracking in that case.

Customization

Customize the widget appearance through your Emporiqa dashboard. No code changes required!

Available Options

Option Description Default
Custom CSS Custom styles for the widget (see below) Default theme
Position Widget button location Bottom Right
Widget Title Header text (supports {store_name}) {store_name}
Greeting Message Initial welcome message Hi! How can I help you today?
Allowed Domains Restrict where widget can be embedded All domains

Custom CSS

Use the Custom CSS field to fully customize the chat widget's appearance. Your CSS is injected into the widget iframe and can override any styles.

CSS Variables

The widget uses CSS variables for colors. Override them in the :root selector:

:root {
  --primary-color: #1A73E8;    /* Send button and accent color */
  --secondary-color: #1669D4;  /* Hover states */
}

Example: Custom Brand Colors

:root {
  --primary-color: #E91E63;    /* Pink brand color */
  --secondary-color: #C2185B;  /* Darker pink for hover */
}

/* Additional customizations */
.btn-primary {
  border-radius: 4px;  /* Square corners */
}

Position Options

Bottom Right
Bottom Left
Top Right
Top Left

Multi-Language Settings

You can configure different titles and messages for each language in your dashboard. The widget automatically detects the customer's language.

Responsive Behavior

Desktop

  • Floating button (56x56px)
  • Expandable chat window
  • Can be maximized to fullscreen
  • Window size: ~50% width, ~80% height

Mobile

  • Full-screen experience
  • Touch-optimized interface
  • Native keyboard handling

The widget automatically adapts to screen size. On screens smaller than 850px, it switches to mobile mode.

Security

Allowed Domains

Restrict where your widget can be embedded by configuring allowed domains in your dashboard. This prevents unauthorized sites from using your widget.

Example: If you set allowed domains to mystore.com, shop.mystore.com, the widget will only work on those domains.

Token Authentication

The widget uses time-limited, HMAC-signed tokens for API authentication. This prevents abuse and ensures requests come from legitimate widget instances.

Rate Limiting

Built-in rate limiting protects against abuse:

  • 10 messages per minute per IP address
  • 100 messages per hour per conversation

Cart Handler

If cart operations are enabled for your store, the widget delegates cart actions (add, remove, update, clear, view, checkout) to a JavaScript function on your page. The plugins for Drupal Commerce, WooCommerce, Sylius, and Magento 2 implement this automatically.

For custom platforms, register EmporiqaCartHandler before the widget loads:

window.EmporiqaCartHandler = async function({ action, items }) {
  const item = items?.[0];

  if (action === 'add') {
    const res = await fetch('/api/cart/add', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        product_id: item.product_id,
        variation_id: item.variation_id,
        quantity: item.quantity
      })
    });
    return await res.json();
  }

  if (action === 'view') {
    const res = await fetch('/api/cart');
    return await res.json();
  }

  if (action === 'checkout') {
    return { success: true, checkoutUrl: '/checkout' };
  }

  // handle remove, update, clear similarly
};

Response Format

Every handler call must resolve with this structure:

{
  "success": true,
  "checkoutUrl": "/checkout/2",
  "cart": {
    "items": [
      {
        "product_id": "257",
        "variation_id": "1097",
        "name": "iPhone 14 - Midnight, 128GB",
        "quantity": 1,
        "unit_price": 699.00,
        "image_url": "https://store.com/images/iphone-14.jpg",
        "product_url": "https://store.com/product/iphone-14"
      }
    ],
    "item_count": 3,
    "total": 1397.00,
    "currency": "USD"
  }
}
Field Type Description
success boolean Whether the operation succeeded
checkoutUrl string URL for the checkout page (used by the "Proceed to checkout" button)
cart.items[].unit_price number Price per single unit as a plain number (e.g. 699.00, not "$699.00")
cart.item_count integer Total quantity across all items
cart.total number Cart total as a plain number
cart.currency string ISO 4217 currency code (e.g. USD, EUR)

Important: All prices must be plain numbers, not formatted strings. 699.00 is correct. "$699.00", "699.000000", and "&#36;699.00" are all wrong. The widget handles formatting based on the product's currency and the widget's language setting.

Troubleshooting

Widget button doesn't appear

  • Check that the chat widget is enabled in Store Settings → Store Integration
  • Check that the script is placed before </body>
  • Verify your Store ID is correct
  • Check browser console for JavaScript errors
  • Ensure your subscription is active

Widget shows 'No products synced' error

  • Send your product data via webhooks before using the widget
  • Check that products were successfully synced in your dashboard
  • Ensure the language parameter matches the language of your synced products

Chat responses are slow or not loading

  • Check your store has an active subscription
  • Verify you haven't exceeded your conversation limit (sandbox stores)
  • Check for network/firewall issues

Widget blocked on my domain

  • Check 'Allowed Domains' setting in your dashboard
  • Add your domain to the allowed list
  • Include all variations (www, non-www, subdomains)

Widget conflicts with other scripts

  • The widget uses isolated CSS and JavaScript
  • Try loading the script with defer attribute
  • Check for CSS z-index conflicts

Testing Your Widget

Before going live, test your widget thoroughly:

  1. Ask about products in your catalog
  2. Test product search with various queries
  3. Ask about policies (shipping, returns, etc.)
  4. Test order tracking (if configured): "Where is my order #12345?"
  5. Test on different devices (desktop, tablet, mobile)
  6. Test in different browsers (Chrome, Firefox, Safari)
  7. Verify customization settings are applied

Need Help with Integration?

Our team is here to help with your integration. Whether you need assistance with webhooks, widget embedding, or troubleshooting, just reach out.

Contact Support