Skip to main content

Django SEO Audit

A production-ready Django package for comprehensive SEO auditing of models using Python protocols and automatic rule discovery.

Features

  • Protocol-Based Architecture: Uses Python 3.12+ protocols for clean, loosely-coupled design
  • Automatic Rule Discovery: Rules auto-register when defined - no manual registration needed
  • Auto-Discovery Management Command: Automatically finds and audits any model using SEOAuditableMixin
  • Comprehensive Rule Set: 18 built-in rules across 4 categories:
    • Core SEO: Title length, meta descriptions, keywords, H1 tags
    • Social Media: OpenGraph and Twitter Card optimization
    • Content Quality: Content depth, introduction, resources
    • Technical SEO: Canonical URLs, robots directives, structured data
  • Django Model Mixin: Drop-in mixin with intelligent fallbacks for common field names
  • Extensible: Easy to add custom rules for your specific SEO requirements
  • Beautiful CLI Output: Color-coded results with emoji indicators and actionable suggestions

Installation

From PyPI (when published)

pip install django-seo-audit

From Source (Development)

# In your workspace directory
git clone https://github.com/directory-platform/django-seo-audit.git
cd django-seo-audit
pip install -e .

UV Workspace (Recommended for development)

Add to your workspace pyproject.toml:

[tool.uv.workspace]
members = [
    "your-project",
    "django-seo-audit",
]

Then run:

uv sync

Quick Start

1. Add to Django Settings

# settings.py
INSTALLED_APPS = [
    # ...
    "django_seo_audit",
]

2. Add Mixin to Your Models

# models.py
from django.db import models
from django_seo_audit import SEOAuditableMixin

class Article(SEOAuditableMixin, models.Model):
    name = models.CharField(max_length=200)
    seo_title = models.CharField(max_length=60, blank=True)
    meta_description = models.TextField(max_length=160, blank=True)
    focus_keyphrase = models.CharField(max_length=100, blank=True)

    # ... other fields

The mixin provides intelligent fallbacks:

  • get_seo_title() → seo_title or name
  • get_meta_description() → meta_description or short_description
  • get_h1_tag() → h1_tag or seo_title or name

3. Run SEO Audit

# List all auditable models
python manage.py seo_audit --list-models

# Audit a specific object
python manage.py seo_audit --model blog.Article --slug my-article

# Audit with verbose output and specific categories
python manage.py seo_audit --model blog.Article --slug my-article --verbose --category core_seo

4. Programmatic Usage

from django_seo_audit import SEOAuditor

# Audit any object
article = Article.objects.get(slug="my-article")
auditor = SEOAuditor()
result = auditor.audit_object(article)

# Check results
print(f"SEO Score: {result.overall_score}/10")
print(f"Grade: {result.get_health_grade()}")
print(f"Passing: {result.is_passing()}")

# Get issues by severity
critical_issues = result.get_critical_issues()
warnings = result.get_warnings()
successes = result.get_successes()

Protocols

Django SEO Audit uses Python protocols to define contracts for auditable objects. Your models don't need to inherit from anything - just implement the methods you need.

BasicSEOAuditable

Core SEO methods every model should implement:

from django_seo_audit import BasicSEOAuditable

def get_seo_title(self) -> str: ...
def get_meta_description(self) -> str: ...
def get_canonical_url(self) -> str: ...
def get_focus_keyphrase(self) -> str: ...
def get_secondary_keywords(self) -> str: ...
def get_h1_tag(self) -> str: ...

SocialMediaAuditable

For social sharing optimization:

from django_seo_audit import SocialMediaAuditable

def get_og_title(self) -> str: ...
def get_og_description(self) -> str: ...
def get_og_image_url(self) -> str | None: ...
def get_twitter_title(self) -> str: ...
def get_twitter_description(self) -> str: ...
def get_twitter_image_url(self) -> str | None: ...

ContentAuditable

For content quality assessment:

from django_seo_audit import ContentAuditable

def has_detailed_content(self) -> bool: ...
def get_content_word_count(self) -> int: ...
def get_content_sections_count(self) -> int: ...
def has_introduction_content(self) -> bool: ...
def get_resource_count(self) -> int: ...

TechnicalSEOAuditable

For technical SEO features:

from django_seo_audit import TechnicalSEOAuditable

def get_robots_directive(self) -> str: ...
def get_schema_type(self) -> str: ...
def get_schema_data(self) -> dict | None: ...
def get_breadcrumb_title(self) -> str: ...
def has_custom_canonical_url(self) -> bool: ...

Creating Custom Rules

Creating custom SEO rules is straightforward:

# rules/custom_rules.py
from django_seo_audit import SEORule, SEOResult, SEOStatus
from django_seo_audit.protocols import BasicSEOAuditable

class CustomKeywordDensityRule(SEORule):
    """Check keyword density in content."""

    name = "Keyword Density"
    description = "Ensures focus keyword appears with optimal density"
    category = "custom"
    weight = 3  # 1-5 importance scale

    def check(self, obj: BasicSEOAuditable) -> SEOResult:
        keyword = obj.get_focus_keyphrase()
        # Your logic here

        return SEOResult(
            status=SEOStatus.GOOD,
            message="Keyword density optimal",
            score=10,
        )

Rules are automatically discovered and registered when imported!

Management Command Reference

List Auditable Models

python manage.py seo_audit --list-models

Shows all models using SEOAuditableMixin with object counts.

Audit by Slug

python manage.py seo_audit --model app_label.ModelName --slug object-slug

Audit by Primary Key

python manage.py seo_audit --model app_label.ModelName --pk 42

Filter by Category

python manage.py seo_audit --model blog.Article --slug test \
    --category core_seo \
    --category social_media

Available categories: core_seo, social_media, content, technical_seo

Verbose Output

python manage.py seo_audit --model blog.Article --slug test --verbose

Shows detailed explanations and actionable suggestions for improvements.

Built-in Rules

Core SEO (5 rules)

  • SEO Title Length: Optimal 50-60 characters
  • Meta Description Length: Optimal 150-160 characters
  • Focus Keyphrase: Presence in title and description
  • H1 Tag Optimization: Proper H1 configuration
  • Secondary Keywords: 3-7 keyword variety

Social Media (5 rules)

  • OpenGraph Image: 1200x630px image configuration
  • OpenGraph Title: Up to 95 characters
  • OpenGraph Description: Up to 200 characters
  • Twitter Card Image: Twitter-optimized imagery
  • Twitter Card Title: Up to 70 characters

Content (4 rules)

  • Detailed Content: Comprehensive content sections
  • Introduction Content: Engaging introduction
  • Supporting Resources: Videos, articles, tools
  • Content Depth: 500+ words across sections

Technical SEO (4 rules)

  • Canonical URL: Duplicate content prevention
  • Robots Directive: Proper indexing configuration
  • Structured Data: Schema.org markup
  • Breadcrumb Optimization: Navigation clarity

Architecture

  • Protocol-Based: Uses Python 3.12+ Protocol for structural subtyping
  • Auto-Registration: Rules register via __init_subclass__ metaclass magic
  • Immutable Results: SEOResult uses frozen dataclass for thread-safety
  • Graceful Degradation: Failed rules don't break the entire audit
  • Zero Config: Works out of the box with sensible defaults

Requirements

  • Python 3.12+
  • Django 4.2+

Development

Setup

# Clone repository
git clone https://github.com/heysamtexas/django-seo-audit.git
cd django-seo-audit

# Install with dev dependencies
pip install -e ".[dev]"
# or with uv
uv sync --extra dev

Running Tests

The package includes a comprehensive test suite with 207 tests:

# Run all tests
make test
# or
PYTHONPATH=. uv run python tests/manage.py test

# Run with verbose output
make test-verbose

# Run specific test module
PYTHONPATH=. uv run python tests/manage.py test tests.test_rules

Code Quality

# Run linting
make lint
# or
ruff check src/ tests/

# Auto-format code
make format
# or
ruff format src/ tests/

# Type checking
make typecheck
# or
mypy src/

# Run all checks
make check

Example Models

See tests/example_app/models.py for living documentation:

  • BlogPost: Full SEO implementation
  • Product: Minimal implementation with fallbacks
  • Page: Custom protocol without mixin

Releases and Publishing

This package uses GitHub Actions to automatically publish to PyPI when a new release is created.

Creating a Release

  1. Update version in pyproject.toml:

    [project]
    version = "0.1.1"  # Bump version
    
  2. Commit version bump:

    git add pyproject.toml
    git commit -m "Bump version to 0.1.1"
    git push origin master
    
  3. Create GitHub release:

    # Using GitHub CLI
    gh release create v0.1.1 --title "Release v0.1.1" --notes "Release notes here"
    
    # Or use GitHub web interface
    # Navigate to: https://github.com/heysamtexas/django-seo-audit/releases/new
    
  4. GitHub Actions will automatically:

    • Verify version matches tag
    • Run tests
    • Build package
    • Publish to PyPI

PyPI Trusted Publisher Setup (First Release Only)

Before creating your first release, configure PyPI Trusted Publisher:

  1. Go to PyPI: https://pypi.org/manage/account/publishing/

  2. Add a new pending publisher:

    • PyPI Project Name: django-seo-audit
    • Owner: heysamtexas
    • Repository name: django-seo-audit
    • Workflow name: publish.yml
    • Environment name: (leave blank)
  3. Create first release - PyPI will create the project automatically

No API tokens needed! Trusted Publishers are more secure and maintenance-free.

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-rule)
  3. Commit your changes (git commit -m 'Add amazing SEO rule')
  4. Push to the branch (git push origin feature/amazing-rule)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details.

Credits

Built by the Directory Platform team as part of the directory ecosystem.

Links

Metadata

Release files for django-seo-audit 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-seo-audit 0.2.0
File Size Uploaded
django_seo_audit-0.2.0.tar.gz 51.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-seo-audit 0.2.0
File Interpreter ABI Platform
django_seo_audit-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 78.8 kB

Release files / django_seo_audit-0.2.0.tar.gz

Download URL django_seo_audit-0.2.0.tar.gz
Size 51.7 kB
Tags Source
SHA-256 checksum
How to use checksums
79f7bd377b7d7775eab51069e07cc9c72def8cb361e10465604d75d5d9ce3655
BLAKE2b-256 checksum
How to use checksums
2963a9cb396fd5e2ecdc6f84a2bbeb36cbb04d327d2ab9e8d05bd7316d79fe31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2025.

Transparency log

Release files / django_seo_audit-0.2.0-py3-none-any.whl

Download URL django_seo_audit-0.2.0-py3-none-any.whl
Size 27.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5d74fe1670ac678c2638cc4cc1cf31499d3d20962509bd6179ca56e8a5541b6e
BLAKE2b-256 checksum
How to use checksums
fea94710c183413bee225ffeba77aa5014b0fd57f5b92c6e49d20d96cb8a2855
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page