IZI RANKER
Back to guides

Technical guide

API Integration Guide — Vercel, Netlify, Railway

Automatically pull your content published on iziRanker and display it on your own site, regardless of your host. The code (step 5) is standard Next.js: it works identically on Vercel, Netlify, and Railway — only the configuration (steps 2 through 4 and 6) differs from one host to another.

Requires a developer.

Unlike Shopify or WordPress, nothing here is turnkey: it's your code (step 5) that must display the retrieved content. The most common pitfall is forgetting dangerouslySetInnerHTML around the HTML — without it, the content displays as raw text with visible tags instead of being formatted.

Comment ça marche, en un coup d'œil

Génération IA

iziRanker rédige l'article, la fiche produit ou la page.

Publication API

Le contenu est envoyé sur /api/v1/* via votre clé API.

Votre site

Votre code récupère le contenu avec un simple fetch().

Deploy Hook

iziRanker déclenche automatiquement un rebuild.

En ligne

Le contenu est visible par vos visiteurs, sans action manuelle.

1. Generate your API key

From the Integrations page, in the "iziRanker API" block, click Generate an API key. Copy it immediately: it will never be shown in plain text again afterward.

2. Store the key (environment variable)

Never hardcode the key in your code or expose it in the browser — only use a server-side environment variable, for example named IZIRANKER_API_KEY.

Vercel

Project Settings → Environment Variables → add IZIRANKER_API_KEY with the pasted key → Save.

Netlify

Site configuration → Environment variables → Add a variable → name it IZIRANKER_API_KEY.

Railway

On your project, Variables tab → New Variable IZIRANKER_API_KEY.

3. Create a rebuild trigger

Publishing content from iziRanker doesn't rebuild your site on its own: you need a trigger that notifies your host that there's something new.

Vercel — Deploy Hooks

Project Settings → Git → Deploy Hooks → give it a name and a branch → Create Hook → copy the generated URL.

Netlify — Build Hooks

Site configuration → Build & deploy → Build hooks → Add build hook → copy the generated URL.

Railway

Railway doesn't offer a simple URL to paste like Vercel/Netlify. Two options: manually redeploy from the dashboard (Redeploy button) after each publication, or automate it via the Railway API (requires a project token and an authenticated request — ask your developer if you want this level of automation).

4. Paste the URL into iziRanker

On Vercel or Netlify: paste the URL copied in the previous step into the Deploy Hook field of the "iziRanker API" block on the Integrations page, then save. On every publication, iziRanker automatically calls this URL → your host triggers a new build → your site republishes itself, with no manual action.

On Railway (with no trigger URL), leave this field empty and redeploy manually after each publication, until you set up more advanced automation if needed.

5. The code to copy, by content type

This code works identically on Vercel, Netlify, and Railway (Next.js needs no adaptation depending on the host). Adjust the folder names to your own structure if needed.

Blog Article

Endpoint: /api/v1/articles · response key: articles

List (app/blog/page.tsx):

async function getArticles() {
  const res = await fetch("https://iziranker.com/api/v1/articles", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { articles } = await res.json();
  return articles;
}

export default async function BlogPage() {
  const articles = await getArticles();

  return (
    <div>
      {articles.map((article) => (
        <a key={article.slug} href={`/blog/${article.slug}`}>
          <h2>{article.title}</h2>
          <p>{article.metaDescription}</p>
        </a>
      ))}
    </div>
  );
}

Individual page (app/blog/[slug]/page.tsx):

async function getArticle(slug: string) {
  const res = await fetch("https://iziranker.com/api/v1/articles", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { articles } = await res.json();
  return articles.find((article) => article.slug === slug);
}

export default async function ArticlePage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const article = await getArticle(slug);
  if (!article) return <p>Article introuvable.</p>;

  return (
    <article>
      <h1>{article.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: article.contentHtml }} />
    </article>
  );
}

Product Sheet

Endpoint: /api/v1/products · response key: products

List (app/produits/page.tsx):

async function getProducts() {
  const res = await fetch("https://iziranker.com/api/v1/products", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { products } = await res.json();
  return products;
}

export default async function ProduitsPage() {
  const products = await getProducts();

  return (
    <div>
      {products.map((product) => (
        <a key={product.slug} href={`/produits/${product.slug}`}>
          {product.productImageUrl && <img src={product.productImageUrl} alt={product.title} />}
          <h2>{product.title}</h2>
          {product.price && <p>{product.price} €</p>}
        </a>
      ))}
    </div>
  );
}

Individual page (app/produits/[slug]/page.tsx):

async function getProduct(slug: string) {
  const res = await fetch("https://iziranker.com/api/v1/products", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { products } = await res.json();
  return products.find((product) => product.slug === slug);
}

export default async function ProduitPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const product = await getProduct(slug);
  if (!product) return <p>Produit introuvable.</p>;

  return (
    <article>
      <h1>{product.title}</h1>
      {product.productImageUrl && <img src={product.productImageUrl} alt={product.title} />}
      {product.price && <p>{product.price} €</p>}
      <div dangerouslySetInnerHTML={{ __html: product.contentHtml }} />
    </article>
  );
}

Local Page

Endpoint: /api/v1/local-pages · response key: localPages

List (app/pages-locales/page.tsx):

async function getLocalPages() {
  const res = await fetch("https://iziranker.com/api/v1/local-pages", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { localPages } = await res.json();
  return localPages;
}

export default async function PagesLocalesPage() {
  const localPages = await getLocalPages();

  return (
    <div>
      {localPages.map((page) => (
        <a key={page.slug} href={`/pages-locales/${page.slug}`}>
          <h2>{page.title}</h2>
        </a>
      ))}
    </div>
  );
}

Individual page (app/pages-locales/[slug]/page.tsx):

async function getLocalPage(slug: string) {
  const res = await fetch("https://iziranker.com/api/v1/local-pages", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { localPages } = await res.json();
  return localPages.find((page) => page.slug === slug);
}

export default async function PageLocalePage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const page = await getLocalPage(slug);
  if (!page) return <p>Page introuvable.</p>;

  return (
    <article>
      <h1>{page.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: page.contentHtml }} />
    </article>
  );
}

Service Page

Endpoint: /api/v1/service-pages · response key: servicePages

List (app/services/page.tsx):

async function getServicePages() {
  const res = await fetch("https://iziranker.com/api/v1/service-pages", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { servicePages } = await res.json();
  return servicePages;
}

export default async function ServicesPage() {
  const servicePages = await getServicePages();

  return (
    <div>
      {servicePages.map((page) => (
        <a key={page.slug} href={`/services/${page.slug}`}>
          <h2>{page.title}</h2>
        </a>
      ))}
    </div>
  );
}

Individual page (app/services/[slug]/page.tsx):

async function getServicePage(slug: string) {
  const res = await fetch("https://iziranker.com/api/v1/service-pages", {
    headers: { Authorization: `Bearer ${process.env.IZIRANKER_API_KEY}` },
    next: { revalidate: 3600 },
  });
  const { servicePages } = await res.json();
  return servicePages.find((page) => page.slug === slug);
}

export default async function ServicePagePage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const page = await getServicePage(slug);
  if (!page) return <p>Page introuvable.</p>;

  return (
    <article>
      <h1>{page.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: page.contentHtml }} />
    </article>
  );
}

6. Git configuration

For your code (step 5) to be deployed and republished automatically, your project must be connected to a Git repository (GitHub, GitLab...).

Vercel

On vercel.com/newImport Git Repository → select your repository → Deploy. Every push to the connected branch triggers a new deployment.

Netlify

On app.netlify.comAdd new site → Import an existing project → Deploy with GitHub → select your repository.

Railway

On railway.app/newDeploy from GitHub repo → select your repository.

Once the repository is connected, only step 3/4 (or a manual redeploy for Railway) triggers a republish after each new iziRanker publication — a Git push is only needed when you modify the code yourself.

7. Security

  • Never expose the key in the browser — only server-side or at build time.
  • If it leaks, click Regenerate key from Integrations: the old key is immediately invalidated.