Django customer tracking that respects your architecture
Django has a signal system built precisely for "do something after a model is saved" — and that's the perfect place for TinyCRM. One post_save signal on your User model and every new customer, across every Django app you run, flows into a single unified table.
Installation
pip install tinycrmAdd your API key to your environment:
# .env or environment variable
TINYCRM_API_KEY=tcrm_proj_xxxxxxxxxxxxThree integration patterns for Django
post_save on User or UserProfile. Fires automatically. Keeps tracking out of views.
Call identify() directly in your registration view or DRF perform_create().
Queue identify() as an async Celery task for zero latency impact.
Getting started: Django integration
Option A — Django Signal (recommended)
# accounts/signals.py
import os
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
from tinycrm import TinyCRM
crm = TinyCRM(api_key=os.environ["TINYCRM_API_KEY"])
User = get_user_model()
@receiver(post_save, sender=User)
def sync_user_to_tinycrm(sender, instance, created, **kwargs):
if created:
# Fire-and-forget: errors are swallowed by default
crm.identify(
email=instance.email,
name=instance.get_full_name() or instance.username,
status="free",
params={"date_joined": str(instance.date_joined.date())},
)
# accounts/apps.py
class AccountsConfig(AppConfig):
def ready(self):
import accounts.signals # noqaOption B — Django view (class-based)
# accounts/views.py
import os
from django.contrib.auth import login
from django.views import View
from django.http import JsonResponse
from tinycrm import TinyCRM
crm = TinyCRM(api_key=os.environ["TINYCRM_API_KEY"])
class SignUpView(View):
def post(self, request):
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
# Sync to TinyCRM
crm.identify(
email=user.email,
name=user.get_full_name(),
status="free",
params={"utm_source": request.GET.get("utm_source", "")},
)
return JsonResponse({"ok": True})
return JsonResponse({"errors": form.errors}, status=400)Option C — Django REST Framework ViewSet
# accounts/api/views.py
import os
from rest_framework import generics, status
from rest_framework.response import Response
from tinycrm import TinyCRM
crm = TinyCRM(api_key=os.environ["TINYCRM_API_KEY"])
class RegisterView(generics.CreateAPIView):
serializer_class = RegisterSerializer
def perform_create(self, serializer):
user = serializer.save()
crm.identify(
email=user.email,
name=user.get_full_name(),
status="free",
)Track subscription upgrades
# billing/views.py
import os
import json
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.http import HttpResponse
from tinycrm import TinyCRM
crm = TinyCRM(api_key=os.environ["TINYCRM_API_KEY"])
@csrf_exempt
@require_POST
def stripe_webhook(request):
payload = request.body
event = verify_stripe_signature(payload, request.META.get("HTTP_STRIPE_SIGNATURE"))
if event["type"] == "checkout.session.completed":
email = event["data"]["object"]["customer_email"]
plan = event["data"]["object"]["metadata"].get("plan", "pro")
crm.identify(email=email, status="paid", params={"plan": plan})
return HttpResponse(status=200)Django ecosystem compatibility
Django REST Framework
Call in perform_create() or serializer.save().
Celery
Wrap in async task for high-throughput routes.
django-allauth
Use social_account_added or user_logged_in signals.
dj-stripe
Sync on WEBHOOK_HANDLERS for subscription events.
PostgreSQL + psycopg
The SDK is DB-agnostic — call after any ORM save.
Gunicorn / uvicorn
Works with both sync and async Django deployments.
Django FAQ
Where should I call tinycrm.identify() in a Django app?
The cleanest pattern is a post_save signal on your User model or a custom profile model. Alternatively, call it directly in your registration view or DRF serializer's create() method.
Can I use the TinyCRM SDK with Django REST Framework?
Yes. In DRF, the best place is the create() method of your UserSerializer or the perform_create() method of your registration ViewSet. Both run server-side after the user object is saved to the database.
Should I use Celery to avoid blocking Django views?
The SDK call is a single lightweight HTTP request (under 100ms). For most Django apps, calling it synchronously in the view is fine. For high-traffic endpoints, dispatch a Celery task for zero added latency.
Does the Python SDK work with Django on AWS Lambda (Zappa)?
Yes. The SDK uses the standard requests library (or httpx), both of which work on AWS Lambda. There are no environment-specific dependencies.
See all your Django customers in one place
14-day free trial. No credit card. Works with Django 4+ and DRF.
pip install tinycrm