earlyseo-blog
Drop-in blog integration for Django and Flask — powered by EarlySEO. Articles are authored in the EarlySEO dashboard and rendered in your Python web app.
Quick Start (Recommended)
The fastest way to get started — run the CLI from your project root:
pip install earlyseo-blog
earlyseo-blog
The CLI automatically:
- Detects whether you're using Django or Flask
- Asks for your Site ID (from Dashboard → Integrations → SDK)
- Generates starter templates, URL config, and a
.envfile
Run your dev server and visit /blog — your articles are live.
Manual Setup
If you prefer to configure things yourself:
Django
pip install "earlyseo-blog[django]"
settings.py
INSTALLED_APPS = [
# …
"earlyseo_blog.django",
]
EARLYSEO_SITE_ID = "your-site-id" # from Dashboard → Integrations → SDK
EARLYSEO_BASE_URL = "https://example.com" # optional; used for SDK back links
By default, /blog links back to the same-domain site root and /blog/<slug>/ links back to same-domain /blog. Set EARLYSEO_BASE_URL to force those links to an absolute domain.
urls.py
from django.urls import include, path
urlpatterns = [
path("blog/", include("earlyseo_blog.django.urls")),
]
Visit /blog to see your articles.
Template tags
Override the built-in HTML by creating your own templates:
<!-- templates/earlyseo/blog_list.html -->
{% extends "base.html" %}
{% load earlyseo %}
{% block extra_head %}{% earlyseo_styles %}{% endblock %}
{% block content %}
{% for article in articles %}
<h2><a href="{% url 'earlyseo_blog:blog_detail' slug=article.slug %}">{{ article.title }}</a></h2>
<p>{{ article.meta_description }}</p>
{% endfor %}
{% endblock %}
Available template tags: {% earlyseo_styles %}, {% earlyseo_article_css %}, {% earlyseo_article article %}.
Flask
pip install "earlyseo-blog[flask]"
app.py
from flask import Flask
from earlyseo_blog.flask.views import create_blog_blueprint
app = Flask(__name__)
app.config["EARLYSEO_SITE_ID"] = "your-site-id"
app.config["EARLYSEO_BASE_URL"] = "https://example.com" # optional; used for SDK back links/sitemaps
app.register_blueprint(create_blog_blueprint(), url_prefix="/blog")
Override the built-in HTML by placing templates/earlyseo/blog_list.html and templates/earlyseo/blog_detail.html in your templates folder.
Sitemap
Django
Plug into Django's built-in sitemaps framework:
# settings.py
INSTALLED_APPS = [
# …
"django.contrib.sitemaps",
"earlyseo_blog.django",
]
# urls.py
from django.contrib.sitemaps.views import sitemap
from earlyseo_blog.django.sitemap import EarlySeoBlogSitemap
sitemaps = { "blog": EarlySeoBlogSitemap }
urlpatterns = [
path("blog/", include("earlyseo_blog.django.urls")),
path("sitemap.xml", sitemap, {"sitemaps": sitemaps}, name="sitemap"),
]
Flask
Register a /blog/sitemap.xml route automatically:
from earlyseo_blog.flask.sitemap import register_blog_sitemap
app.config["EARLYSEO_BASE_URL"] = "https://example.com"
register_blog_sitemap(app, url_prefix="/blog")
Or get entries for a custom sitemap:
from earlyseo_blog.flask.sitemap import create_blog_sitemap_entries
entries = create_blog_sitemap_entries(base_url="https://example.com")
Python Client
Use the client directly in any Python app:
from earlyseo_blog import EarlySeoClient
client = EarlySeoClient(site_id="your-site-id")
# List articles (page 1)
page = client.get_list_page(1)
for article in page.articles:
print(article.title, article.slug)
# Get a single article
article = client.get_article("my-article-slug")
print(article.title)
print(article.content_html)
Async Client
from earlyseo_blog import AsyncEarlySeoClient
async def main():
async with AsyncEarlySeoClient(site_id="your-site-id") as client:
page = await client.get_list_page(1)
article = await client.get_article("my-article-slug")
Install the async extra for HTTP/2 support:
pip install "earlyseo-blog[async]"
Models
All responses are validated with Pydantic v2:
| Model | Description |
|---|---|
Manifest |
Site manifest with total pages/articles |
ArticleListItem |
Summary for list views |
ArticleListPage |
Paginated list of ArticleListItem |
Article |
Full article with content_html |
from earlyseo_blog.models import Article, Manifest
CSS
Built-in styles for article content and blog layout:
from earlyseo_blog.css import ARTICLE_CSS, BLOG_CSS
Include them in your <style> tag or template to get default styling.
Configuration
| Setting | Description | Default |
|---|---|---|
site_id |
Your EarlySEO site ID (required) | — |
Django: Set EARLYSEO_SITE_ID in settings.py.
Flask: Set in app.config["EARLYSEO_SITE_ID"].
Requirements
- Python ≥ 3.9
- httpx ≥ 0.24
- pydantic ≥ 2.0
- Django ≥ 4.2 (for Django integration)
- Flask ≥ 2.3 (for Flask integration)
License
Proprietary — see LICENSE for details.
Metadata
Release files for earlyseo-blog 1.0.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| earlyseo_blog-1.0.6.tar.gz | 17.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| earlyseo_blog-1.0.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.0 kB
Release files / earlyseo_blog-1.0.6.tar.gz
| Download URL | earlyseo_blog-1.0.6.tar.gz |
|---|---|
| Size | 17.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3515891acf8601c094435c50be401da31efa693f22348d67e5093e1e71cb63f4
|
|
BLAKE2b-256 checksum How to use checksums |
9b7e73d3b69e979da7c0adc2a5e4b8fd99ad5d61e3c0df54dd8d6a0495b4b159
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.8.0 pkginfo/1.12.1.2 readme-renderer/42.0 requests/2.33.1 requests-toolbelt/1.0.0 urllib3/2.6.3 tqdm/4.67.3 importlib-metadata/9.0.0 keyring/25.7.0 rfc3986/2.0.0 colorama/0.4.6 CPython/3.11.10
|
Release files / earlyseo_blog-1.0.6-py3-none-any.whl
| Download URL | earlyseo_blog-1.0.6-py3-none-any.whl |
|---|---|
| Size | 22.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e95040e1f1061713eb3e19028e5138ca4d791ff1e4f0efb118eee5bf6feaefaf
|
|
BLAKE2b-256 checksum How to use checksums |
7b5bc6035e6f35dd4becad815e5c20b9d53bdce2c78b5d7600cd068ae01b529b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.8.0 pkginfo/1.12.1.2 readme-renderer/42.0 requests/2.33.1 requests-toolbelt/1.0.0 urllib3/2.6.3 tqdm/4.67.3 importlib-metadata/9.0.0 keyring/25.7.0 rfc3986/2.0.0 colorama/0.4.6 CPython/3.11.10
|