Files
vibn-agent-runner/vibn-attribution-package/README.md

8.3 KiB

🚀 Vibn Marketing Attribution & Identity Sync SDK

A modular, highly scalable, and decoupled SDK package to link anonymous site traffic tracking (Umami Analytics) with registered user profiles (Vibn Database), providing comprehensive First-Touch Marketing Attribution and acquisition logs.

Developed originally for Missinglettr and structured specifically to be drop-in ready for the Vibn Platform architecture.


📁 Package Inventory

This package contains three decoupled layers designed to be copied directly into your respective repositories:

Path Purpose Language / Framework
frontend/VibnTracker.tsx Client-side search params listener, sessionStorage / Cookie persistence, automated Umami injection, and session identity bridging (identify()). TypeScript / Next.js React
backend/models.py Abstract Base Django Model adding UTM and Referrer fields to any User / Client record. Python / Django
backend/mixins.py Django REST Framework (DRF) interceptor mixin to auto-capture attribution variables from incoming signup payloads. Python / Django REST Framework
umami-bridge/umami_service.py Reusable bridge to pull aggregated pageviews, session timestamps, and raw click-trails from Umami (via REST API or raw DB joins). Python / Django

🏛️ Architecture Overview

The system bridges anonymous traffic with database records using a secure Identity Exchange:

[Anonymous Visitor Clicks Ad / Tweet]
              │
              ▼
[Lands on Website with UTMs & Referrer]
              │  ├── Auto-logged in Umami (analytics.vibnai.com)
              │  └── Cached client-side in sessionStorage & Cookie fallback
              ▼
[Signs Up / Logs in via Google OAuth]
              │
              ▼
[Frontend POSTs Signup payload + UTM params to Backend]
              │
              ▼
[Django Backend saves user record + permanently binds UTM columns]
              │
              ▼
[Frontend calls useVibnTracker.identify(user_id)]
              │
              ▼
[Umami merges ALL previous anonymous browsing history with this new User ID!]

💻 Step-by-Step Implementation Guide

1. Frontend Integration (Vibn Next.js Web App)

Copy frontend/VibnTracker.tsx into your Next.js project (e.g., inside components/metrics/VibnTracker.tsx):

A. Wrap your Root Layout:

In app/layout.tsx (or your entry file), wrap the tree with VibnTrackerProvider. This will automatically inject your Umami tracking script and listen for UTM parameters across your landing and console domains:

import { VibnTrackerProvider } from "@/components/metrics/VibnTracker";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <VibnTrackerProvider 
        umamiWebsiteId="your-umami-website-uuid" 
        umamiScriptUrl="https://analytics.vibnai.com/script.js"
      >
        <body>{children}</body>
      </VibnTrackerProvider>
    </html>
  );
}

B. Capture & Send on Signup / Google OAuth exchange:

In your signup or Google OAuth exchange page (where the user completes registration), extract the cached attribution parameters using the useVibnTracker hook and send them in the request body to your backend:

import { useVibnTracker } from "@/components/metrics/VibnTracker";

export default function GoogleCallbackPage() {
  const { getStoredAttribution, identify, track } = useVibnTracker();

  const handleOAuthSignup = async (googleToken: string) => {
    // 1. Get first-touch parameters cached in browser
    const attribution = getStoredAttribution();

    // 2. POST to your register endpoint
    const response = await fetch("/api/auth/register", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        google_token: googleToken,
        ...attribution // Sends utm_source, utm_medium, utm_campaign, referrer, etc.
      })
    });

    if (response.ok) {
      const user = await response.json();

      // 3. BRIDGING IDENTITY: Link anonymous browser history with real user ID!
      identify({
        userId: user.id, // Primary key in your database
        email: user.email,
        name: user.name,
        plan: user.plan
      });

      // 4. Track custom sign-up conversion in Umami
      track("user_completed_signup", { plan: user.plan });
    }
  };
  
  // ...
}

2. Backend Integration (Vibn Django API)

Copy backend/models.py and backend/mixins.py into your Django apps.

A. Inherit from the Abstract Model:

Add first-touch marketing attribution columns to your active User or APIClient model by inheriting from VibnAbstractAttributionModel:

# your_app/models.py
from backend.models import VibnAbstractAttributionModel

class UserProfile(VibnAbstractAttributionModel):
    # Your existing fields
    email = models.EmailField(unique=True)
    name = models.CharField(max_length=255)
    
    class Meta:
        db_table = "user_profile"

Then generate and apply your database migrations:

python manage.py makemigrations
python manage.py migrate

B. Intercept requests with the DRF View Mixin:

Add the VibnAttributionCaptureMixin to your Signup or Authentication API ViewSet. It will automatically intercept, extract, and write the UTM parameters into the saving model:

# your_app/views.py
from rest_framework import viewsets
from backend.mixins import VibnAttributionCaptureMixin
from .models import UserProfile
from .serializers import UserProfileSerializer

class RegisterViewSet(VibnAttributionCaptureMixin, viewsets.ModelViewSet):
    """
    User registration API view. 
    VibnAttributionCaptureMixin automatically grabs utm_source, utm_campaign,
    and Referrer headers from requests and binds them onto the UserProfile on save.
    """
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer

3. Expose Live Traffic Trails in Admin Consoles

Copy umami-bridge/umami_service.py into your Python services.

You can securely query stats directly from your Umami self-hosted database (read-only) inside your Admin panels, allowing you to render actual pageviews, device breakdowns, and exact visitor session timelines for any specific client.

A. Configure Umami DB Connection:

In Django's settings.py, register your Umami database:

DATABASES = {
    'default': {
        # Your main application DB
    },
    'umami_db': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'umami_production_db',
        'USER': 'readonly_user',
        'PASSWORD': 'password',
        'HOST': '34.19.250.135',
        'PORT': '5432',
    }
}

B. Fetch Live Session Data for Admin Console:

In your Admin API view (e.g. admin_user_detail), call the service to fetch raw click-trails:

# your_admin_app/views.py
from rest_framework.response import Response
from umami_bridge.umami_service import VibnUmamiService

def get_admin_user_profile(request, user_id):
    # Initialize service
    umami = VibnUmamiService()
    
    # 1. Fetch total web sessions, total pageviews, and first interaction timestamp
    funnel = umami.get_aggregated_funnel_for_user(user_id, db_connection_name="umami_db")
    
    # 2. Fetch the actual 50 most recent page clicks, devices, and browsers used by this client!
    click_trail = umami.get_user_session_click_trail(user_id, db_connection_name="umami_db")
    
    return Response({
        "user_id": user_id,
        "first_touch_web_funnel": funnel,
        "live_click_trail": click_trail
    })

🛡️ Best Practices & GDPR Compliance

  1. Self-Hosted Privacy: Because Umami is hosted on your domain (analytics.vibnai.com), cookie and script blockades are minimized, and no data is shared with third parties (complying strictly with GDPR, CCPA, and PECR).
  2. First-Touch Preservation: The mixin uses if not client.utm_source: checks on save, ensuring first-touch parameters (the exact ad or link that originally brought the user in) are preserved and never overwritten by subsequent organic logins.
  3. No Database Blockades: The umami_service.py uses read-only connections and limits queries to LIMIT 50 to make sure raw analytics querying never causes performance blocks on your main application database thread.