# Flask SDK Guide (/docs/flask-sdk)



Quick Start with CLI [#quick-start-with-cli]

The fastest way to add EarlySEO to your Flask project:

```bash
pip install "earlyseo-blog[flask]"
earlyseo-blog
```

The CLI will:

1. Detect your Flask project
2. Ask for your **Site ID** (from Dashboard → Integrations → SDK)
3. Generate starter templates and a `.env` file

> Prefer manual setup? Follow the steps below.

***

Prerequisites [#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 [#installation]

```bash
pip install "earlyseo-blog[flask]"
```

This installs the core package plus Flask-specific extras (blueprint, Jinja helpers).

***

Blueprint Setup [#blueprint-setup]

Register the EarlySEO blog blueprint in your Flask app:

```python
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:

```python
import os

app.config["EARLYSEO_SITE_ID"] = os.environ.get("EARLYSEO_SITE_ID", "")
```

***

Routes [#routes]

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:

```python
app.register_blueprint(blog_bp, url_prefix="/articles")
```

***

Built-in Templates [#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 [#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 [#blog-list-template]

Create `templates/earlyseo/blog_list.html`:

```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 [#blog-detail-template]

Create `templates/earlyseo/blog_detail.html`:

```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 [#full-app-example]

A minimal Flask app with EarlySEO blog:

```python
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:

```bash
export EARLYSEO_SITE_ID=your-site-id
python app.py
```

Visit `http://localhost:5000/blog` to see your articles.

***

Using the Client Directly [#using-the-client-directly]

For API endpoints or custom logic, use the client directly:

```python
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) [#async-client-with-quart-or-async-flask]

```python
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:

```bash
pip install "earlyseo-blog[async]"
```

***

How Publishing Works [#how-publishing-works]

1. Write and publish an article in the EarlySEO dashboard
2. EarlySEO delivers your articles via a high-performance API
3. Your Flask app fetches articles at request time via the `earlyseo-blog` package
4. Articles include SEO metadata automatically

***

Need Help? [#need-help]

* [Python SDK Overview](/docs/python-sdk)
* [Django SDK Guide](/docs/django-sdk)
* [SDK Sitemap Guide](/docs/sdk-sitemap)
* [SDK Integration Setup](/docs/sdk)
* [SDK Troubleshooting](/docs/sdk-troubleshooting)
* Email [team@earlyseo.com](mailto:team@earlyseo.com)
