Skip to content
Documentation menu: Django

Django integration

Add theBizness.ai analytics to your Django application with template integration and robust configuration.

Setup time

5 minutes

Difficulty

Medium

Performance

Pythonic

Choose your implementation method

Base template method

Add analytics to your base template with context processors

Step 1: Environment variables

Add to your .env file:

# .env
ANALYTICS_ENABLED=True
ANALYTICS_WEBSITE_ID=your-website-id
ANALYTICS_DOMAIN=yourdomain.com

Step 2: Update the settings

# settings.py

import os
from decouple import config  # pip install python-decouple

# Analytics Configuration
ANALYTICS_ENABLED = config('ANALYTICS_ENABLED', default=False, cast=bool)
ANALYTICS_WEBSITE_ID = config('ANALYTICS_WEBSITE_ID', default='')
ANALYTICS_DOMAIN = config('ANALYTICS_DOMAIN', default='')
ANALYTICS_SCRIPT_URL = config('ANALYTICS_SCRIPT_URL', default='https://thebizness.ai/js/script.js')

# Context processors (add to TEMPLATES settings)
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'myapp.context_processors.analytics',  # Add this line
            ],
        },
    },
]

Step 3: Create the context processor

# myapp/context_processors.py

from django.conf import settings

def analytics(request):
    """
    Add analytics configuration to template context
    """
    return {
        'ANALYTICS_ENABLED': getattr(settings, 'ANALYTICS_ENABLED', False),
        'ANALYTICS_WEBSITE_ID': getattr(settings, 'ANALYTICS_WEBSITE_ID', ''),
        'ANALYTICS_DOMAIN': getattr(settings, 'ANALYTICS_DOMAIN', ''),
        'ANALYTICS_SCRIPT_URL': getattr(settings, 'ANALYTICS_SCRIPT_URL', 'https://thebizness.ai/js/script.js'),
    }

Step 4: Update the base template

<!-- templates/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}My Django App{% endblock %}</title>
    
    {% block extra_css %}{% endblock %}
    
    <!-- theBizness Analytics -->
    {% if ANALYTICS_ENABLED and ANALYTICS_WEBSITE_ID %}
        <script 
            async 
            defer 
            data-website-id="{{ ANALYTICS_WEBSITE_ID }}" 
            data-domain="{{ ANALYTICS_DOMAIN|default:request.get_host }}" 
            src="https://thebizness.ai/js/script.js">
        </script>
    {% endif %}
</head>
<body>
    {% block content %}{% endblock %}
    
    {% block extra_js %}{% endblock %}
</body>
</html>
Django best practices
  • • Environment-based configuration
  • • Context processor for template availability
  • • Auto-detection of domain from request
  • • Easy to disable for development

Middleware implementation

Automatically inject analytics script using Django middleware

Create the analytics middleware

# myapp/middleware.py

from django.conf import settings
from django.utils.html import escape
from django.utils.safestring import mark_safe

class AnalyticsMiddleware:
    """
    Middleware to inject analytics script into HTML responses
    """
    
    def __init__(self, get_response):
        self.get_response = get_response
        
    def __call__(self, request):
        response = self.get_response(request)
        
        # Leave excluded paths untouched (the admin site by default, set ANALYTICS_EXCLUDE_PATHS to change it)
        excluded = getattr(settings, 'ANALYTICS_EXCLUDE_PATHS', ('/admin/',))
        if request.path.startswith(tuple(excluded)):
            return response

        # Only inject on HTML responses. Streamed or encoded bodies (for example gzipped by GZipMiddleware) are left alone
        if (
            getattr(settings, 'ANALYTICS_ENABLED', False) and
            response.get('Content-Type', '').startswith('text/html') and
            response.status_code == 200 and
            not response.streaming and
            not response.has_header('Content-Encoding')
        ):
            analytics_script = self._get_analytics_script(request)
            if analytics_script:
                charset = response.charset
                content = response.content.decode(charset)
                content = content.replace('</head>', f'{analytics_script}</head>')
                response.content = content.encode(charset)
                response['Content-Length'] = len(response.content)
        
        return response
    
    def _get_analytics_script(self, request):
        website_id = getattr(settings, 'ANALYTICS_WEBSITE_ID', '')
        domain = getattr(settings, 'ANALYTICS_DOMAIN', '') or request.get_host()
        script_url = getattr(settings, 'ANALYTICS_SCRIPT_URL', 'https://thebizness.ai/js/script.js')
        
        if not website_id:
            return ''
            
        return f'''
    <script async defer data-website-id="{escape(website_id)}" data-domain="{escape(domain)}" src="{escape(script_url)}"></script>'''

Register the middleware

Add to settings.py MIDDLEWARE list:

MIDDLEWARE = [
    # ... other middleware
    'myapp.middleware.AnalyticsMiddleware',
]

Place it below GZipMiddleware and any other middleware that changes the response body: Django passes responses up the list from the bottom, so a class placed above GZipMiddleware sees the compressed body and adds no script.

Custom template tag

Create reusable template tags for analytics

Create the template tags

# myapp/templatetags/analytics_tags.py

from django import template
from django.conf import settings
from django.utils.html import escape
from django.utils.safestring import mark_safe

register = template.Library()

@register.simple_tag(takes_context=True)
def analytics_script(context):
    """
    Template tag to render analytics script
    Usage: {% load analytics_tags %} {% analytics_script %}
    """
    request = context.get('request')
    
    if not getattr(settings, 'ANALYTICS_ENABLED', False):
        return ''
    
    website_id = getattr(settings, 'ANALYTICS_WEBSITE_ID', '')
    if not website_id:
        return ''
    
    domain = getattr(settings, 'ANALYTICS_DOMAIN', '')
    if not domain and request:
        domain = request.get_host()
    
    script_url = getattr(settings, 'ANALYTICS_SCRIPT_URL', 'https://thebizness.ai/js/script.js')
    
    script = f'''<script async defer data-website-id="{escape(website_id)}" data-domain="{escape(domain)}" src="{escape(script_url)}"></script>'''
    
    return mark_safe(script)

@register.filter
def is_analytics_enabled(value):
    """
    Template filter to check if analytics is enabled
    Usage: {% if request|is_analytics_enabled %}
    """
    return getattr(settings, 'ANALYTICS_ENABLED', False)

Usage in templates

<!-- Load the template tags -->
{% load analytics_tags %}

<!-- Use in your template head -->
{% analytics_script %}

<!-- Conditional usage -->
{% if request|is_analytics_enabled %}
    <p>Analytics is enabled</p>
{% endif %}

Management command and app config

Advanced setup with management commands and app configuration

Management command

# management/commands/setup_analytics.py

from django.core.management.base import BaseCommand
from django.conf import settings
import os

class Command(BaseCommand):
    help = 'Setup theBizness analytics configuration'
    
    def add_arguments(self, parser):
        parser.add_argument('website_id', type=str, help='Your theBizness website ID')
        parser.add_argument('--domain', type=str, help='Your domain (optional)')
        parser.add_argument('--env-file', type=str, default='.env', help='Environment file path')
    
    def handle(self, *args, **options):
        website_id = options['website_id']
        domain = options.get('domain', '')
        env_file = options['env_file']
        
        # Update or create .env file
        env_vars = {
            'ANALYTICS_ENABLED': 'True',
            'ANALYTICS_WEBSITE_ID': website_id,
        }
        
        if domain:
            env_vars['ANALYTICS_DOMAIN'] = domain
        
        self._update_env_file(env_file, env_vars)
        
        self.stdout.write(
            self.style.SUCCESS(
                f'Analytics configuration updated successfully!\n'
                f'Website ID: {website_id}\n'
                f'Domain: {domain or "Auto-detected"}'
            )
        )
        
        if not domain:
            self.stdout.write(
                self.style.WARNING(
                    'No domain specified. Domain will be auto-detected from request.'
                )
            )
    
    def _update_env_file(self, env_file, variables):
        """Update or create environment file with new variables"""
        env_path = os.path.join(settings.BASE_DIR, env_file)

        # Read existing lines so comments, blank lines and their order are kept
        lines = []
        if os.path.exists(env_path):
            with open(env_path, 'r') as f:
                lines = f.read().splitlines()

        # Replace the value of each existing variable in place, and leave every other line as it was
        pending = dict(variables)
        for i, line in enumerate(lines):
            key = line.split('=', 1)[0].strip()
            if '=' in line and key in variables:
                lines[i] = f'{key}={variables[key]}'
                pending.pop(key, None)

        # Append the variables the file did not have yet
        lines.extend(f'{key}={value}' for key, value in pending.items())

        # Write back to file
        with open(env_path, 'w') as f:
            f.write('\n'.join(lines) + '\n')

App configuration

# myapp/apps.py

from django.apps import AppConfig
from django.conf import settings

class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'
    
    def ready(self):
        # Validate analytics configuration on startup
        self._validate_analytics_config()
    
    def _validate_analytics_config(self):
        if getattr(settings, 'ANALYTICS_ENABLED', False):
            website_id = getattr(settings, 'ANALYTICS_WEBSITE_ID', '')
            if not website_id:
                import warnings
                warnings.warn(
                    'Analytics is enabled but ANALYTICS_WEBSITE_ID is not set. '
                    'Analytics tracking will not work.',
                    RuntimeWarning
                )

Usage

# Setup analytics with management command
python manage.py setup_analytics your-website-id --domain yourdomain.com

# Install python-decouple for environment variables
pip install python-decouple

Verify installation

Test your Django analytics integration

Development check

  1. 1. Run python manage.py runserver to check that the page loads
  2. 2. Visit your Django app
  3. 3. View page source to check script
  4. 4. Check browser DevTools Network tab for script.js. The console shows a "Tracking disabled on localhost" warning here, which is expected

Django specific

  1. 1. Test with different views/URLs
  2. 2. Check admin interface (should NOT have script)
  3. 3. Verify environment variables
  4. 4. Test with DEBUG=False
Django-specific tips
  • • The tracker does nothing on localhost, *.local, *.test, private IP addresses or file:// pages. It logs a "Tracking disabled on localhost" warning in the console. Verify on a publicly reachable domain.
  • • Use different settings for development/production
  • • Consider disabling analytics in DEBUG mode
  • • Test with both authenticated and anonymous users
  • • Make sure ALLOWED_HOSTS includes your domain
  • • If your site sends a Content-Security-Policy header, allow https://thebizness.ai in script-src and connect-src. Blocked requests show only as CSP errors in the browser console

Django integration complete

Your Django application is now tracking analytics with Python elegance. Here's what to explore next:

Revenue attribution

Connect Stripe or send a purchase event from your order-complete page

Custom events

Send events from the browser with window.thebizness(...)

Server-side reporting

Report sales from a view with the requests library and your ingest secret as a Bearer token. Keep the secret in an environment variable