Introducing the Opinly SDK v1: your content, your domain, any framework
We just shipped Opinly SDK v1, a complete headless rebuild of how you pull Opinly-managed content into your own site. If you write with Opinly and publish on your own stack, this release makes that clean, typed, and framework-agnostic.
The short version: your blog now lives on your domain, rendered by your app, with the SEO and LLM-visibility plumbing already done for you. No hosted subdomain and no locked-in UI.
Why we built it
Opinly exists to win you traffic from Google and from LLMs. Both have a hard technical prerequisite that no amount of good writing gets around: the content has to live on your own domain, be server-rendered, and ship clean structured data.
Search still rewards your root domain. Moving a blog off a subdomain and onto a subdirectory of the main site has repeatedly produced double-digit organic lifts, because the authority compounds on your domain rather than a separate one.
LLMs cite what they can read and trust. Answer engines (ChatGPT, Perplexity, Google AI Overviews) pull from content that is machine-readable, structured for extraction, and sitting on an authoritative domain. Content stuck behind a client-rendered widget or on a low-authority hosted subdomain doesn't make the cut.
Structured data is the entry ticket. JSON-LD, correct metadata, sitemaps and RSS are what let both crawlers and RAG pipelines understand and quote your pages.
Our old SDK didn't help you here. It shipped a bundled Next.js blog component (one framework, one opinionated UI) and talked to the server over an internal transport whose types drifted from the client. That was fine for dropping in a blog. It was the wrong shape for owning your SEO surface.
v1 flips the model: Opinly gives you structured data and rendering primitives, and you own the page, the URL, and the domain.
What's in v1
The SDK is now a set of small, composable packages. Take only what you need.
The data client
@opinly/backend: a typedfetchclient over our new/v1HTTP + OpenAPI content API. Bearer auth, cursor-paginatedposts,post(slug),categories,authors,routes,rss, and webhook types. Every type is generated from the OpenAPI spec, so the client can't silently drift from the server. That whole class of bug is gone.
The renderer + SEO core
@opinly/shared: a framework-agnostic, zero-runtime-dependency renderer for Opinly content, plus the SEO toolkit: JSON-LD builders (BlogPosting, FAQ, Breadcrumb, Person, Collection),buildMetadata, prefix-aware URL helpers, sitemap/RSS builders, reading-time and heading extraction. It renders our content model directly, so we don't ship a heavy editor engine to your users, and the HTML serializer is XSS-safe by default.
Framework renderers. A real <OpinlyContent> for the stack you already run:
@opinly/react·@opinly/vue·@opinly/svelte
Framework SEO adapters. These wire metadata into the head the idiomatic way:
@opinly/next·@opinly/nuxt·@opinly/sveltekit(@opinly/nextalso wires image optimization viawithOpinlyConfig)
React, Vue, Svelte, Next, Nuxt and SvelteKit are all first-class. And because the contract underneath is plain HTTP/JSON with a published OpenAPI spec, any language or framework can consume it, even where we don't ship an adapter yet. The REST API reference documents the raw contract.
What it looks like
Fetch content with the typed client:
import { createOpinlyClient } from "@opinly/backend";
const opinly = createOpinlyClient({ apiKey: process.env.OPINLY_API_KEY });
const { data: posts } = await opinly.posts({ limit: 10 });
const post = await opinly.post("my-first-post"); // FullPost | null
Render it in your own page. This is React, but the same shape works in Vue and Svelte:
import { OpinlyContent } from "@opinly/react";
export default function Post({ post }) {
return <OpinlyContent content={post.content} config={{ imagesPrefix: "/images" }} />;
}
Ship the SEO signals that get you found and cited:
import { buildBlogPostingJsonLd, buildMetadata } from "@opinly/shared";
const jsonLd = buildBlogPostingJsonLd(post); // structured data for search + LLMs
const meta = buildMetadata(post); // title, description, canonical, OG
opinly.routes() gives you every addressable URL for your sitemap and static generation, and opinly.rss() gives you a ready-to-serve feed.
The upgrade path
v1 is the new major for
@opinly/backendand@opinly/next, and the first release of the framework packages.The 0.x line stays published and keeps working against the old endpoint — nothing you're running today breaks.
The bundled Next blog UI still ships in
@opinly/nextbut is now deprecated, with pointers to the headless primitives. It'll be removed only in a later, signposted major.
Migrate when you're ready. The case for doing it soon is simple: content rendered on your own domain with real structured data earns you search rankings and AI citations, and content behind the old widget doesn't.
Get started
Install the client and the renderer for your stack:
npm install @opinly/backend @opinly/react # or @opinly/vue, @opinly/svelte
Grab your API key from Opinly, point it at /v1, and you're pulling live content in a few lines. The quickstart takes you from install to a rendered post in about five minutes, and there are guides for Next.js, Nuxt, SvelteKit, React and Vue, plus runnable example apps for Next (App and Pages router), Nuxt, and SvelteKit to copy from.
If you're building with an AI assistant or an AI builder like Cursor or v0, the entire docs site ships as one Markdown file at llms-full.txt to drop into context.
Full documentation lives at opinly.ai/docs.
Content ranks and gets cited when it lives on your domain, in your app. SDK v1 gets it there.
Get started with Opinly to put your traffic on auto-pilot
Don't wait for the perfect moment. Start building your SEO and LLM presence today with Opinly.
