vTilt
Why vTiltHow It WorksFeaturesFAQDocs
Docs / Django
Quick startEvent forwarding
MCP server
Guides
OverviewAuthenticationOAuthAgent skills (prompts)AI intelligenceGoogle Ads
Client setup
CursorClaude DesktopVS CodeCodex
Realtime
Debug ViewRealtime Dashboard
Integration guides
Frontend frameworks
Next.jsNuxt.jsVue.jsReactReact RouterRemixGatsbySvelte / SvelteKitAstroAngularTanStack StartDocusaurus
Backend frameworks
NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails
Backend languages
PythonPHPRubyElixirGoJava.NET / C#Rust
Stack guides
Vue + PHP
SDK
Browser SDK
InstallScript bundlesEvent trackingAutocaptureIdentify & aliasWeb VitalsSession recordingChat widgetFeature readinessRemote configurationReverse proxyDebug logging
Node SDK
Install & setupCapture, identify & aliasContext & shutdown

Documentation

vTilt
Quick startEvent forwarding

MCP server

Realtime

Debug ViewRealtime Dashboard

Integration guides

NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails

SDK

DocsIntegration guidesDjango

Django

Integrate vTilt with Django — render the SDK in your base template, identify on every authenticated request, send server-side events over HTTP.

There's no native Python SDK yet, but vTilt's wire format is a plain JSON POST so any Python code can emit events. The pattern below covers the two pieces that matter: the Browser SDK (rendered into your Django base template) and a thin Python helper for server-side captures.

#1. Configure settings

# settings.py
import os

VTILT_TOKEN = os.environ['VTILT_TOKEN']
VTILT_HOST = os.environ.get('VTILT_HOST', 'https://www.vtilt.com')
python

#2. Pass the user into your base template

Use a context processor so vtilt_context is available in every template render.

# myproject/context_processors.py
from django.conf import settings

def vtilt(request):
    user = request.user if request.user.is_authenticated else None
    return {
        'vtilt_context': {
            'token': settings.VTILT_TOKEN,
            'host': settings.VTILT_HOST,
            'user': {
                'id': str(user.id),
                'email': user.email,
            } if user else None,
        }
    }
python
# settings.py (continued)
TEMPLATES = [{
    'OPTIONS': {
        'context_processors': [
            # ...
            'myproject.context_processors.vtilt',
        ],
    },
}]
python

#3. Render the SDK in your base template

{# templates/base.html #}
<!doctype html>
<html lang="en">
<head>
  <script>
    window.__vtilt = {{ vtilt_context|safe }};
  </script>
  <script>
    !(function(t,e){/* ...vTilt loader snippet from Quick start... */})(document, window.vt || []);

    vt.init(window.__vtilt.token, {
      api_host: window.__vtilt.host,
      autocapture: true,
      capture_pageview: true,
      capture_pageleave: true,
    });

    if (window.__vtilt.user) {
      vt.identify(window.__vtilt.user.id, { email: window.__vtilt.user.email });
    }
  </script>
</head>
<body>{% block content %}{% endblock %}</body>
</html>
django

Important

Important: Identifying users in the base template means every authenticated page-load identifies — not just login. This is the most common bug to avoid; see Identify & alias for the full model.

#4. Server-side capture helper

For events that fire outside a browser session (webhooks, scheduled jobs, server-side conversions), POST directly to vTilt.

# myproject/vtilt.py
import json
from urllib.request import Request, urlopen
from django.conf import settings


def vtilt_capture(distinct_id: str, event: str, properties: dict | None = None) -> None:
    payload = json.dumps({
        'api_key': settings.VTILT_TOKEN,
        'event': event,
        'distinct_id': distinct_id,
        'properties': properties or {},
    }).encode('utf-8')

    req = Request(
        f'{settings.VTILT_HOST}/api/e',
        data=payload,
        headers={'Content-Type': 'application/json'},
        method='POST',
    )
    try:
        urlopen(req, timeout=2).read()
    except Exception:
        pass  # never block the response on analytics
python
# views.py
from .vtilt import vtilt_capture

def checkout_complete(request):
    vtilt_capture(
        distinct_id=str(request.user.id),
        event='purchase_completed',
        properties={'amount': 99.99},
    )
    return JsonResponse({'ok': True})
python

Tip

Tip: Run vtilt_capture from a Celery task or transaction.on_commit so analytics never blocks the user-facing response. Network failures shouldn't surface to your users.

#Next steps

  • Identify & alias — anonymous → known user merge.
  • Flask integration guide — same Python pattern, smaller framework.
  • Event forwarding — fan events out to GA4, Meta CAPI, PostHog.
PreviousCloudflare WorkersIntegration guidesNextFlaskIntegration guides

On this page

  • 1. Configure settings
  • 2. Pass the user into your base template
  • 3. Render the SDK in your base template
  • 4. Server-side capture helper
  • Next steps