Headless CMS setup guide for HTML/CSS/JS developers without frameworks

6 replies
Last updated: Jan 28, 2026
Hey guys, I just want to get something off my chest. I think it's pretty hard to get a guide on how to use the headless CMS for people who only know HTML CSS and vanilla JS. Maybe it's me who is just not skilled enough for this but I think many topics are not explained well. For instance I didn't get a clear guide on how to setup a very basic headless CMS for my portfolio and how I would connect it. I either found overkilling guides which would be too much setup for my case or It's that I need to setup with react, gatsby, nextjs or the like.
Again, maybe it's only because I'm too unskilled to get it, I don't know.
AI Update

I hear your frustration, and you're absolutely right – there's a gap in documentation for folks who want to use Sanity with just vanilla HTML, CSS, and JavaScript. You're not unskilled at all; the ecosystem has indeed focused heavily on framework-specific guides, and that makes it harder to see the simple path. Let me give you a straightforward explanation of how to set this up for a basic portfolio.

The Two-Part Setup

Sanity splits into two pieces:

  1. Sanity Studio - where you manage/edit content (this needs Node.js for initial setup)
  2. Your actual website - which can be pure HTML/CSS/JS

Step 1: Set Up Studio (One-Time Thing)

You'll need Node.js installed just to create the Studio. Run:

npm create sanity@latest

Follow the prompts - it'll ask you to create a project, choose a schema template (pick "blog" or "clean" for simplicity), and deploy. This gives you a Studio at yourproject.sanity.studio where you'll add your portfolio projects, blog posts, or whatever content you want.

Step 2: Fetch Content with Plain JavaScript

This is the part that should be simpler to find! Once you have content in your Studio, you can fetch it from any HTML page using Sanity's Query API. It's just a regular HTTP endpoint that returns JSON.

Here's a complete working example:

<!DOCTYPE html>
<html>
<head>
    <title>My Portfolio</title>
    <style>
        .project { margin: 20px; padding: 20px; border: 1px solid #ccc; }
    </style>
</head>
<body>
    <h1>My Projects</h1>
    <div id="projects"></div>

    <script>
        // Get these from your Sanity project settings
        const projectId = 'YOUR_PROJECT_ID';
        const dataset = 'production';
        
        // GROQ query (Sanity's query language - similar to SQL)
        const query = '*[_type == "project"]';
        const encodedQuery = encodeURIComponent(query);
        
        const url = `https://${projectId}.api.sanity.io/v2021-10-21/data/query/${dataset}?query=${encodedQuery}`;

        fetch(url)
            .then(response => response.json())
            .then(data => {
                const projects = data.result;
                const container = document.getElementById('projects');
                
                projects.forEach(project => {
                    const div = document.createElement('div');
                    div.className = 'project';
                    div.innerHTML = `
                        <h2>${project.title}</h2>
                        <p>${project.description || ''}</p>
                    `;
                    container.appendChild(div);
                });
            })
            .catch(error => console.error('Error fetching projects:', error));
    </script>
</body>
</html>

Handling Images

Images in Sanity need special URL construction. When you get an image reference from Sanity, it looks like image-abc123-1200x800-jpg. You can build the URL manually:

function buildImageUrl(imageAsset, projectId, dataset) {
    const ref = imageAsset.asset._ref;
    // ref format: "image-{id}-{width}x{height}-{format}"
    const parts = ref.split('-');
    const id = parts[1];
    const dimensions = parts[2];
    const format = parts[3];
    
    return `https://cdn.sanity.io/images/${projectId}/${dataset}/${id}-${dimensions}.${format}`;
}

Or you can use the @sanity/image-url package if you want transformations (resizing, cropping, format conversion), though that requires installing via NPM. For a truly vanilla setup, the manual URL building above works fine.

Why This Feels Hidden

You're right that this should be more prominent. The reason framework guides dominate is:

  • Sanity Studio itself is built with React (but you only use it as an editor, not in your code)
  • Frameworks handle image optimization and live preview features automatically
  • Most tutorials assume you're building a "modern" app with a build step

But the core truth: Sanity is just an HTTP API that returns JSON. You can absolutely use it with vanilla JavaScript.

What You Need to Know

  1. Your project ID (found in Sanity project settings)
  2. GROQ - Sanity's query language (it's like SQL but for JSON)
  3. The Query API endpoint format: https://{projectId}.api.sanity.io/v2021-10-21/data/query/{dataset}?query={your-query}

That's it! No React, no Next.js, no build tools needed for your actual website.

A Quick GROQ Primer

  • *[_type == "project"] - Get all documents of type "project"
  • *[_type == "project"][0..5] - Get first 6 projects
  • *[_type == "project"]{title, description, image} - Only return specific fields

The Studio setup is the only "complex" part, and even that's just running one command. Once that's done, you're just making fetch requests to get JSON data – exactly what you'd do with any other API.

Show original thread
6 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?