Skip to main content

easeo

Deterministic SEO metadata generation for content platforms.

Generate canonical URLs, titles, descriptions, robots directives, Open Graph, Twitter Cards, and JSON-LD from content entities. One Rust core with Python, Node.js, and Rust APIs.

PyPI npm crates.io Python Rust Tests Docs License

What is easeo

easeo is a deterministic SEO metadata generator. It takes a content entity, the route it lives at, and a site-wide configuration, and returns a complete SEO payload: canonical URL, title, description, robots directives, Open Graph, Twitter Cards, and JSON-LD.

All logic lives in the Rust core (easeo-core). The Python and Node.js packages wrap the same engine, so the same entity, route, and config produce identical output in every language. The cross-language conformance suite asserts that byte for byte.

The tutorial walks through installation and a first payload. Concepts explains the entity model, fallback chains, URL normalization, and validation rules.

Content Entity
      |
      v
   easeo
      |
      +-- canonical URL
      +-- title & description
      +-- robots directives
      +-- Open Graph
      +-- Twitter Cards
      +-- JSON-LD
      |
      v
 Deterministic Payload

Quick start

Every binding exposes the same call: pass an entity, a route, and a config, and get a payload back. The full tutorial covers configuration, overrides, rendering, and contracts.

Python

pip install easeo
from easeo import SEOConfig, SEOEntity, build_seo_payload

config = SEOConfig(
    canonical_host="example.com",
    public_base_url="https://example.com",
)

entity = SEOEntity(
    entity_type="post",
    title="Hello World",
    excerpt="An example post.",
)

payload = build_seo_payload(entity, "/blog/hello", config)
print(payload.render_html())

JavaScript / TypeScript

npm install @easeo/core
import { buildSeoPayload } from "@easeo/core";

const payload = buildSeoPayload(
  { entityType: "post", title: "Hello World", description: "An example post." },
  "/blog/hello",
  { canonicalHost: "example.com", publicBaseUrl: "https://example.com" }
);

console.log(payload.renderHtml());

Rust

cargo add easeo-core
use easeo_core::{SEOConfig, SEOEntity, EntityType, build_seo_payload};

let config = SEOConfig {
    canonical_host: "example.com".into(),
    public_base_url: "https://example.com".into(),
    ..Default::default()
};

let entity = SEOEntity {
    entity_type: EntityType::Post,
    title: Some("Hello World".into()),
    excerpt: Some("An example post.".into()),
    ..Default::default()
};

let payload = build_seo_payload(&entity, "/blog/hello", &config).unwrap();
assert_eq!(payload.canonical, "https://example.com/blog/hello");

Why easeo

Other SEO libraries do too much (scoring, keyword analysis, content rewriting), while easeo does one thing and does it well: generate deterministic SEO metadata from content entities.

Given the same inputs, easeo always produces the same output. No timestamps, no randomness, no environment reads, no hidden I/O. This makes SEO metadata something you can:

  • snapshot test: assert against expected payloads
  • hash: generate stable ETags
  • cache: safely memoize results
  • diff: detect changes across builds
  • validate in CI: commit your SEO intent as code with contracts

See Why easeo for the design goals and a comparison with other SEO tooling.

What easeo is not

  • Not a scoring or keyword analysis tool.
  • Not a crawler or site auditor.
  • Not a content rewriter or generator.
  • Not a runtime service. It is a pure function over its inputs.
  • Not a full page renderer. It renders a head snippet, not a document.

Features

  • 11 entity types: home, post, page, video, taxonomy, search, product, organization, local_business, faq, other. See the entity model
  • URL normalization: HTTPS enforcement, lowercase paths, trailing slash control, duplicate slash collapse, tracking parameter removal. See URL normalization
  • JSON-LD schemas: WebSite, WebPage, Article, Product, Organization, LocalBusiness, FAQPage, BreadcrumbList, plus custom schemas via registry. See JSON-LD schemas and custom JSON-LD
  • Open Graph: full og:type, title, description, image, locale, audio, video
  • Twitter Cards: summary_large_image by default, with image alt, site, creator
  • Robots directives: index/noindex, follow/nofollow, max-snippet, max-image-preview, max-video-preview
  • SEO contracts: machine-readable SEO intent for CI validation. See the contract reference
  • Validation: built-in checks for title length, description, canonical format, OG image, robots directives. See validation
  • Hashing: SHA-256 payload hashing and ETag generation
  • HTML rendering: complete head snippet with meta tags, OG, Twitter, JSON-LD
  • Extension points: config-scoped hooks and schema registries. See hooks

Learn more in the guides and start from a recipe such as a blog post, product page, or search results page.

Packages

Package Registry Purpose
easeo PyPI Python bindings for the Rust core
easeo[fastapi], easeo[django], easeo[flask], easeo[zensical] PyPI extras Framework adapters and the docs extension
@easeo/core npm Node.js bindings for the Rust core
easeo-core crates.io Pure Rust engine with no I/O dependencies

Integrations

Per-framework setup guides live in the Integrations docs.

JavaScript / TypeScript

Framework Package API
Next.js @easeo/next easeoMetadata() returns a Next.js Metadata object
Astro @easeo/astro Build-time integration with contract emission
Vite @easeo/vite transformIndexHtml hook
Nuxt @easeo/nuxt useEaseoSeo() composable
SvelteKit @easeo/sveltekit buildEaseoPayload() and <EaseoHead />
React @easeo/react <EaseoHead /> component

Python

Framework Import
FastAPI from easeo.adapters.fastapi import EaseoSEO
Django from easeo.adapters.django import seo_head
Flask from easeo.adapters.flask import Easeo
Zensical from easeo.contrib.zensical import EaseoExtension

API

Symbol Description
build_seo_payload(entity, route_path, config, overrides=None) Builds the deterministic SEOPayload
SEOConfig Site-wide configuration: host, base URL, defaults, hooks, registries
SEOEntity Content entity: type, title, excerpt, images, dates, breadcrumbs, FAQ, product fields
SEOOverrides Highest-precedence per-call overrides
SEOPayload Output with render_html(), to_dict(), to_json(), hash(), and etag()
URLPolicy Canonical URL normalization policy
build_seo_contract Builds a machine-readable SEO contract
validate_payload Runs the built-in validation checks
HookRegistry, SchemaRegistry Config-scoped post-processing and JSON-LD generators
SEOEntityBuilder, from_blog_post, from_product, from_faq Ergonomic entity constructors

Names are shown in Python. JavaScript uses camelCase and Rust uses snake_case. Full signatures live in the Python, JavaScript, and Rust API references.

Documentation

  • Tutorial: installation, first payload, rendering, contracts, configuration
  • Concepts: determinism, entity and payload models, fallback chains, URL normalization, schemas, validation
  • Guides: custom JSON-LD, hooks, contracts in CI, framework recipes
  • Reference: Python, JavaScript, and Rust APIs, contracts, errors
  • Integrations: per-framework setup
  • Recipes: blog post, product page, category page, search results
  • Examples: core and framework examples for every binding

LLM-friendly versions: llms.txt and llms-full.txt.

Building

# Rust core
cargo build --workspace --release

# Python bindings
pip install maturin
maturin develop -m crates/easeo-python/Cargo.toml

# Node bindings
npm install -g @napi-rs/cli@^3
cd packages/core
napi build --platform --release --manifest-path ../../crates/easeo-node/Cargo.toml
cp ../../crates/easeo-node/*.node .

Testing

# Rust
cargo test --workspace

# Python
pytest tests/python/

# JavaScript
node --test tests/javascript/*.cjs

# Cross-language conformance
python tests/conformance/test_conformance.py

Next steps

Contributors

License

MIT

Metadata

Release files for easeo 0.1.1

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

Built distributions (wheels)

Table of built distributions (wheels) for easeo 0.1.1
File
easeo-0.1.1-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
easeo-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
easeo-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
easeo-0.1.1-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
easeo-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 3.7 MB

Release files / easeo-0.1.1-cp310-abi3-win_amd64.whl

Download URL easeo-0.1.1-cp310-abi3-win_amd64.whl
Size 621.8 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
c0c8f5bd8487fe13673ccf3f6e327089c3e25f35ffa932fe5167a92275b5f935
BLAKE2b-256 checksum
How to use checksums
d7353fe75b69cbdb4e15cb5f9b76d233015b968a5c5139680bfc21ea582db916
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 1, 2026.

Transparency log

Release files / easeo-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL easeo-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 798.4 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
e90d8ca8f6381b659ccfe03dea4aa5e664b3f6c50ed4d592676cb1b424c24799
BLAKE2b-256 checksum
How to use checksums
2a161387a45fc564ae9f87c3a08f208e7d43d68acb5c8ff9f4999e937a926aac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 1, 2026.

Transparency log

Release files / easeo-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL easeo-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 784.9 kB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
11d87e43110e1fcb8257a9d0847936373cc05af4145c2b6e173ee84611be839c
BLAKE2b-256 checksum
How to use checksums
8e33cd9517d3f6a0098565fb10bbff6045687d4027fb6c5a6ed0ccc2f25b363e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 1, 2026.

Transparency log

Release files / easeo-0.1.1-cp310-abi3-macosx_11_0_arm64.whl

Download URL easeo-0.1.1-cp310-abi3-macosx_11_0_arm64.whl
Size 723.7 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
8fbe6e28c055b04c281e45620cfbc554eb2b61041f27c01960cd942b60729d25
BLAKE2b-256 checksum
How to use checksums
b98a678f11c7fd0a47756c9457186b9440b7d4abb4f4b4a812edabf06d4437b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 1, 2026.

Transparency log

Release files / easeo-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl

Download URL easeo-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl
Size 734.4 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
e2f333afeb67ebc4ebafe4956a19ced5045d2a04e61caa51f94013deb3c3c5a6
BLAKE2b-256 checksum
How to use checksums
ee4283bed92c03bcfc4d185f96190f2b1152630df0ff9538f7f98be268b2e221
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 1, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.0

5 release files

This release

0.1.1 This release

5 release files

0.1.0

5 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