Flask SDK Guide
Add an EarlySEO blog to your Flask application with the earlyseo-blog Python package. Blueprint setup, Jinja templates, and configuration.
Quick Start with CLI
The fastest way to add EarlySEO to your Flask project:
pip install "earlyseo-blog[flask]"
earlyseo-blogThe CLI will:
- Detect your Flask project
- Ask for your Site ID (from Dashboard → Integrations → SDK)
- Generate starter templates and a
.envfile
Prefer manual setup? Follow the steps below.
Prerequisites
- Python ≥ 3.9
- Flask ≥ 2.0
- SDK integration enabled in EarlySEO (Dashboard → Integrations → SDK)
- Site ID from the SDK integration card
- At least one published article
Installation
pip install "earlyseo-blog[flask]"This installs the core package plus Flask-specific extras (blueprint, Jinja helpers).
Blueprint Setup
Register the EarlySEO blog blueprint in your Flask app:
from flask import Flask
from earlyseo_blog.flask.views import create_blog_blueprint
app = Flask(__name__)
app.config["EARLYSEO_SITE_ID"] = "your-site-id"
blog_bp = create_blog_blueprint()
app.register_blueprint(blog_bp, url_prefix="/blog")Or load the Site ID from an environment variable:
import os
app.config["EARLYSEO_SITE_ID"] = os.environ.get("EARLYSEO_SITE_ID", "")Optional: Custom CDN URL
app.config["EARLYSEO_CDN_BASE_URL"] = "https://media.earlyseo.com" # defaultRoutes
The blueprint registers two routes:
| URL Pattern | Name | Description |
|---|---|---|
/blog/ | earlyseo_blog.blog_list | Paginated article list (?page=N) |
/blog/<slug>/ | earlyseo_blog.blog_detail | Single article view |
You can change the prefix when registering the blueprint:
app.register_blueprint(blog_bp, url_prefix="/articles")Built-in Templates
The package ships with built-in HTML that renders a clean blog layout out of the box. No template files are required to get started — just register the blueprint and visit /blog/.
Custom Jinja Templates
To customize the look of your blog, create template files in your project's templates/earlyseo/ directory. Flask will use your templates instead of the built-in ones.
Blog list template
Create templates/earlyseo/blog_list.html:
{% raw %}
{% extends "base.html" %}
{% block head %}
<style>{{ article_css }}{{ blog_css }}</style>
{% endblock %}
{% block content %}
<h1>Blog</h1>
{% for article in articles %}
<article>
{% if article.featured_image_url %}
<img src="{{ article.featured_image_url }}" alt="{{ article.title }}" />
{% endif %}
<h2>
<a href="{{ url_for('earlyseo_blog.blog_detail', slug=article.slug) }}">
{{ article.title }}
</a>
</h2>
<p>{{ article.meta_description }}</p>
</article>
{% endfor %}
<!-- Pagination -->
<nav>
{% if current_page > 1 %}
<a href="?page={{ current_page - 1 }}">← Previous</a>
{% endif %}
<span>Page {{ current_page }} of {{ total_pages }}</span>
{% if current_page < total_pages %}
<a href="?page={{ current_page + 1 }}">Next →</a>
{% endif %}
</nav>
{% endblock %}
{% endraw %}Context variables available:
| Variable | Type | Description |
|---|---|---|
articles | list | List of ArticleListItem objects |
current_page | int | Current page number |
total_pages | int | Total number of pages |
total_articles | int | Total article count |
article_css | str | Article-specific CSS |
blog_css | str | Blog layout CSS |
Blog detail template
Create templates/earlyseo/blog_detail.html:
{% raw %}
{% extends "base.html" %}
{% block title %}{{ article.title }}{% endblock %}
{% block head %}
<style>{{ article_css }}{{ blog_css }}</style>
<meta name="description" content="{{ article.meta_description }}" />
{% endblock %}
{% block content %}
<article>
<h1>{{ article.title }}</h1>
{% if article.featured_image_url %}
<img src="{{ article.featured_image_url }}" alt="{{ article.title }}" />
{% endif %}
{{ content_html | safe }}
</article>
{% endblock %}
{% endraw %}Context variables available:
| Variable | Type | Description |
|---|---|---|
article | Article | Full article object |
content_html | str | Rendered HTML of the article body |
article_css | str | Article-specific CSS |
blog_css | str | Blog layout CSS |
Full App Example
A minimal Flask app with EarlySEO blog:
import os
from flask import Flask
from earlyseo_blog.flask.views import create_blog_blueprint
app = Flask(__name__)
app.config["EARLYSEO_SITE_ID"] = os.environ["EARLYSEO_SITE_ID"]
app.register_blueprint(create_blog_blueprint(), url_prefix="/blog")
@app.route("/")
def home():
return '<h1>My Site</h1><p><a href="/blog">Read the blog</a></p>'
if __name__ == "__main__":
app.run(debug=True)Run it:
export EARLYSEO_SITE_ID=your-site-id
python app.pyVisit http://localhost:5000/blog to see your articles.
Using the Client Directly
For API endpoints or custom logic, use the client directly:
from flask import jsonify
from earlyseo_blog import EarlySeoClient
@app.route("/api/articles")
def api_articles():
client = EarlySeoClient(site_id=app.config["EARLYSEO_SITE_ID"])
page = client.get_list_page(1)
return jsonify({
"articles": [{"title": a.title, "slug": a.slug} for a in page.articles]
})Async client (with Quart or async Flask)
from earlyseo_blog import AsyncEarlySeoClient
async with AsyncEarlySeoClient(site_id="your-site-id") as client:
page = await client.get_list_page(1)Install the async extra:
pip install "earlyseo-blog[async]"How Publishing Works
- Write and publish an article in the EarlySEO dashboard
- EarlySEO writes JSON files to the global CDN
- Your Flask app fetches JSON at request time via the
earlyseo-blogpackage - Articles include SEO metadata automatically