Flask
Integrate vTilt with Flask — render the SDK in your Jinja 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 Jinja base template) and a thin Python helper for server-side captures.
#1. Configure environment
# .env
VTILT_TOKEN=YOUR_PROJECT_TOKEN
VTILT_HOST=https://www.vtilt.comtext
#2. Inject the user into every template
Use @app.context_processor to make a vtilt_context object available to every template render.
# app.py
import os
from flask import Flask, render_template
from flask_login import current_user
app = Flask(__name__)
VTILT_TOKEN = os.environ['VTILT_TOKEN']
VTILT_HOST = os.environ.get('VTILT_HOST', 'https://www.vtilt.com')
@app.context_processor
def inject_vtilt():
user = (
{'id': str(current_user.id), 'email': current_user.email}
if current_user.is_authenticated
else None
)
return {
'vtilt_context': {
'token': VTILT_TOKEN,
'host': VTILT_HOST,
'user': user,
}
}python
#3. Render the SDK in your base template
{# templates/base.html #}
<!doctype html>
<html lang="en">
<head>
<script>
window.__vtilt = {{ vtilt_context | tojson }};
</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>jinja
#4. Server-side capture helper
For events that fire outside a browser session — webhooks, scheduled jobs, server-side conversions — POST directly to vTilt.
# vtilt.py
import json
from urllib.request import Request, urlopen
def vtilt_capture(token: str, host: str, distinct_id: str, event: str, properties: dict | None = None) -> None:
payload = json.dumps({
'api_key': token,
'event': event,
'distinct_id': distinct_id,
'properties': properties or {},
}).encode('utf-8')
req = Request(
f'{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 analyticspython
# routes.py
from .vtilt import vtilt_capture
@app.route('/checkout', methods=['POST'])
def checkout():
vtilt_capture(
VTILT_TOKEN, VTILT_HOST,
distinct_id=str(current_user.id),
event='purchase_completed',
properties={'amount': 99.99},
)
return {'ok': True}python
#Next steps
- Identify & alias — anonymous → known user merge.
- Django integration guide — same Python pattern, larger framework.
- Event forwarding — fan events out to GA4, Meta CAPI, PostHog.