vTilt
By roleFoundersKnow what to fix firstMarketersSee what happens after the clickCMOsSee what your budget really buys
By businessSaaSTurn signups into active usersEcommerceSee why shoppers abandon cartsAgenciesProve your work to clientsEnterpriseOne customer record for every team
MeasureWeb AnalyticsFind where buyers leaveSession ReplaySee why they left, not just that they didAdsKnow what paid visitors do nextIntegrationsOne snippet feeds your stack
ThinkPeopleOne profile per customerCustomer MemoryvTilt remembers every visitorSite KnowledgeAnswers and audits from your own pages
ActAsk AIAnswers from real behaviorAI ChatChat that knows the visitorEmail CampaignsEmail from real visits
PricingWhy vTiltDocs
Docs / Flask
Getting Started
OverviewInstallInitializeIdentify usersTrack eventsLogout & resetVerify eventsCommon mistakes
Guides
Event forwardingReverse proxyRealtime dashboardSite knowledge
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
API Reference
Browser SDK
Script bundlesAutocaptureWeb VitalsSession recordingChat widgetFeature readinessRemote configurationDebug logging
Node SDK
Install & setupCapture, identify & aliasContext & shutdownGlobal properties & opt-outError tracking
MCP server
Guides
OverviewAuthenticationOAuthAgent skills (prompts)AI intelligenceSite knowledgeGoogle AdsMeta Ads
Client setup
CursorClaude DesktopVS CodeCodex

Getting Started

OverviewInstallInitializeIdentify usersTrack eventsLogout & resetVerify eventsCommon mistakes

Guides

Event forwardingReverse proxyRealtime dashboardSite knowledge
NestJSHonoCloudflare WorkersDjangoFlaskLaravelPhoenixRuby on Rails

API Reference

MCP server

On this page

On this page

  • 1. Configure environment
  • 2. Inject the user into every template
  • 3. Render the SDK in your base template
  • 4. Server-side capture helper
  • Next steps
DocsGuidesBackend frameworksFlask

Flask

Last updated July 22, 2026

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.com
text

#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

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.

# 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 analytics
python
# 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

Tip

For low-latency endpoints, run vtilt_capture in a background thread or push it to a job queue (RQ, Celery). Analytics shouldn't block your user-facing response.

#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.
  • Common mistakes — integration pitfalls to avoid before you ship.
PreviousDjangoIntegration guidesNextLaravelIntegration guides