
Replacing some features of Yoast or SEMrush for Django & Django-CMS users.
In other words, django-check-seo will tell you if you have problems concerning a broad range of SEO aspects of your pages.
Requirements
- Python 3.8+ & Django 2.2+
> Still using Python 2? Version <0.6 from this branch is for you! - Django Check SEO relies on Django site framework + define a new permission
- beautifulsoup4 (>= 4.7.0)
- htmx (a version is included in Django Check SEO static files)
Install
-
Install the module from PyPI:
python3 -m pip install django-check-seo -
Add it in your
INSTALLED_APPS:"django_check_seo", -
Add this in your
urls.py(add it before thecms.urlsline if you're using django CMS):path("django-check-seo/", include("django_check_seo.urls")), -
Update your Django Site objet with a working url (website url for prod env, localhost:8000 for your dev environment).
-
Add
testserverto yourALLOWED_HOSTS(django-check-seo uses the Test Framework in order to get content, instead of doing a regular HTTP request). -
Add the permission (
use_django_check_seo) to the users/groups you want to let access Django Check SEO. -
(optional) Configure the settings (see config below).
-

Misc
This application may be used with or without django-cms (a "Check SEO" button will appear in the CMS toolbar if you're using django-cms).
If you're not using Django CMS (only Django), here's the link format to access your pages reports (with or without using i18n):
https://example.com/django-check-seo/?page=/example-page/
https://example.com/fr/django-check-seo/?page=/example-page/
Settings
Keywords handling 
Keywords are discovered via a configurable function. Set it's import path in your settings:
# Default: read from html page <meta name="keywords" content="..."> (comma-separated)
DJANGO_CHECK_SEO_KEYWORDS_DISCOVERY_METHOD = "django_check_seo.utils.keywords_discovery.meta_keywords"
To use keywords stored in the database (models Page and Keyword from Django Check SEO), set this instead:
DJANGO_CHECK_SEO_KEYWORDS_DISCOVERY_METHOD = "django_check_seo.utils.keywords_discovery.model_keywords"
# Set/update keywords through Django Check SEO page:
DJANGO_CHECK_SEO_KEYWORDS_EDITABLE = True
You're free to implement your own solution to handle keywords.
Select main content (exclude header/footer/...)
Since django-check-seo will count things like number of words on the main content and the number of internal links, it is important to only select the main content of the page (an address in the footer is not the main content of your page).
Django-check-seo use a string (named DJANGO_CHECK_SEO_EXCLUDE_CONTENT) of css selectors to exclude unwanted html nodes from the html content:
DJANGO_CHECK_SEO_EXCLUDE_CONTENT = "tag, .class, #id, tag > .child_class"
Example: See this issue's comment for an example.
You can find a reference table of css selectors explained here (on mdn docs).
Basic config
The basic config (used by default) is located in django-check-seo/conf/settings.py and looks like this:
DJANGO_CHECK_SEO_SETTINGS = {
"content_words_number": [300, 600],
"internal_links": 1,
"external_links": 1,
"meta_title_length": [30, 60],
"meta_description_length": [50, 160],
"keywords_in_first_words": 50,
"max_link_depth": 3,
"max_url_length": 70,
}
If you need to change something, just define a dict named DJANGO_CHECK_SEO_SETTINGS in your settings.py.
Custom config example:
If you put this in your settings.py file:
DJANGO_CHECK_SEO_SETTINGS = {
"internal_links": 25,
"meta_title_length": [15,30],
}
Then this will be the settings used by the application:
DJANGO_CHECK_SEO_SETTINGS = {
"content_words_number": [300, 600],
"internal_links": 25, # 1 if using default settings
"external_links": 1,
"meta_title_length": [15,30], # [30, 60] if using default settings
"meta_description_length": [50, 160],
"keywords_in_first_words": 50,
"max_link_depth": 3,
"max_url_length": 70,
}
Want to know more ? See the wiki page Config explained.
Templates
The django_check_seo/default.html template have an <aside> block named seo_aside that you can replace if you want, using the extends & {% block seo_aside %} instructions, like this:
{% extends "django_check_seo/default.html" %}
{% block seo_aside %}
Hi!
{% endblock seo_aside %}
This template will remplace all the
About/Documentation&Raw data(content on the<aside>block) by "Hi!".
Want a video?
https://github.com/user-attachments/assets/a12dd23c-548d-4566-b1e8-4f300c80be7c
How the keywords works.
Want a screenshot?

Other (older) screenshots and videos are available on the wiki.
Unit tests
They are located in tests folder.
# Create test venv & install dependencies
python3 -m venv .venv && . .venv/bin/activate && python3 -m pip install django bs4 lxml djangocms-page-meta requests pytest pytest-django pytest-cov unidecode "hypothesis[django]"
Launch tests
# Souce venv, launch tests (including coverage & fuzzy testing)
. .venv/bin/activate && python3 -m pytest -s --cov-config=.coveragerc --cov=django_check_seo --cov-report term-missing # -s --hypothesis-verbosity=verbose # if you want to see the values tested by hypothesis)
Contributing
See CONTRIBUTING.md.