Support APIQuick starts by stack

Quick start: Django

Django 4.2+, Python ≥ 3.9. About 15 minutes to a verified chat message.

pip install gauge-support
export GAUGE_APP_ID=<app id> GAUGE_IDENTITY_SECRET=<identity secret> GAUGE_WEBHOOK_SECRET=<whsec_…>

1 and 3. Two views: support/views.py

import logging
import os

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_GET, require_POST

from gauge_support import mint_integration_token, verify_webhook

log = logging.getLogger(__name__)
_handled = set()  # use your database in production: ids repeat on retries and resends


@require_GET
@login_required
def gauge_token(request):
    token = mint_integration_token(
        os.environ["GAUGE_IDENTITY_SECRET"],
        app_id=os.environ["GAUGE_APP_ID"],
        user_id=str(request.user.pk),
        integration="customer",
        email=request.user.email or None,
    )
    response = JsonResponse({"token": token})
    response["Cache-Control"] = "no-store"
    return response


@csrf_exempt  # Gauge signs the request instead; the signature is the CSRF defence here
@require_POST
def gauge_webhook(request):
    result = verify_webhook(os.environ["GAUGE_WEBHOOK_SECRET"], request.body, request.headers)
    if not result.valid:
        return HttpResponseBadRequest(result.reason)
    event = result.event
    if event["id"] not in _handled:
        _handled.add(event["id"])
        log.info("gauge %s %s", event["event"], event["id"])
    return HttpResponse(status=200)

request.body is the raw bytes, which is what the signature covers. urls.py:

from django.urls import path
from support import views

urlpatterns = [
    path("gauge-token", views.gauge_token),
    path("gauge/webhooks", views.gauge_webhook),
]

2. The widget (your page)

<script src="https://widget.gauge.chat/v1/<version>/widget.js"
  integrity="sha384-<integrity>" crossorigin="anonymous" async></script>
<script>
  window.addEventListener('load', function () {
    window.PulseWebchat.init({
      apiUrl: 'https://app.gauge.chat/backend',
      connectionId: '<chat connection id>',
      supportMode: true,
      integration: 'customer',
      getToken: function () { // called on every open, so the token is always fresh
        return fetch('/gauge-token', { credentials: 'include' })
          .then(function (r) { return r.json(); })
          .then(function (j) { return j.token; });
      },
    });
  });
</script>

CSP: script-src https://widget.gauge.chat and connect-src https://app.gauge.chat wss://app.gauge.chat. Signed-out visitors: leave out getToken; they chat anonymously where the Integration allows it. Check my site (Developers → Support) fetches your page and tells you if the snippet, its integrity and the connection id are right.

4. Check it

  1. Sign in to your site as a test user (in the sandbox: Seed test customers, then sign in as test_customer_1), open the widget and send "hello". In the console the conversation shows the user's name and Verified. Not verified? Paste the JSON from /gauge-token into Developers → Support → Token checker: it names the rule that failed.
  2. Developers → Webhooks → your endpoint → Send test event, pick support.chat.message_created: the result says Delivered · 200 and your log shows the event id. Change one byte of the secret in your env and send again: your handler answers 400 bad_signature.

Server was down? Replay failed on the same page resends everything that did not land.

On this page