Wagtail Headless CMS Setup Guide
We integrate Wagtail API for headless mode with GraphQL and webhooks—it's a great approach, but you'll quickly hit limitations of the built-in REST API v2 if you need mutations or previews. For example, an e-commerce catalog with 50,000 products needed draft previews before publication; the standard API doesn't expose drafts, so we wrote a custom endpoint with a token. For a blog with regular posts, we needed instant page revalidation on Next.js, so we implemented webhooks from scratch. Our experience shows these problems are solvable in 2–4 days using GraphQL and custom endpoints. Typical project cost ranges from $4,000 to $8,000, and clients save on average $10,000 in development costs.
Wagtail's API is read-only by default — official documentation.
Why the standard Wagtail API doesn't solve headless project challenges?
First, read-only. To create or update a page via API, you need GraphQL or django-rest-framework with custom views. Second, page previews are a separate saga. Wagtail doesn't expose drafts via API; you need a dedicated PreviewAPIViewSet and a token. Third, images are returned without transformations—renditions must be built in the serializer. GraphQL with a dataloader is 3 times faster than REST when fetching related data—this is confirmed on our projects. In one project, we accelerated catalog page loading from 3 seconds to 0.4 seconds by switching to GraphQL.
| Criterion | REST API v2 | GraphQL (Strawberry) |
|---|---|---|
| Mutations | No | Yes, full CRUD |
| Draft preview | Published only | Via custom endpoints |
| Query flexibility | Fixed fields | Fetch only needed fields |
| Performance | N+1 problem | Solved via dataloader |
How to set up mutations with GraphQL?
We use Strawberry Django — it provides schema auto-generation, subscription support, and typing via decorators. Here's a minimal configuration:
# settings.py INSTALLED_APPS = [ 'strawberry.django', ... ] # schema.py import strawberry from wagtail.models import Page from strawberry.django import auto @strawberry.django.type(model=Page) class PageType: id: auto title: auto slug: auto @strawberry.type class Query: pages: list[PageType] = strawberry.django.field() @strawberry.type class Mutation: @strawberry.mutation def create_page(self, title: str, slug: str) -> PageType: page = Page(title=title, slug=slug) page.save() return page schema = strawberry.Schema(query=Query, mutation=Mutation) Register the endpoint:
# urls.py from strawberry.django.views import GraphQLView urlpatterns += [ path('graphql/', GraphQLView.as_view(schema=schema)), ] Also set up CORS if the frontend is on a different domain. Use django-cors-headers.
How to set up preview and revalidation via webhook?
Typical case: a static site on Next.js that renders pages server-side (SSR) or incrementally (ISR). When a page is published, Wagtail must notify Next.js to clear the cache. Wagtail does not send webhooks natively—we implement via signals.
# blog/signals.py from wagtail.signals import page_published, page_unpublished import httpx def revalidate_page(sender, instance, **kwargs): slug = instance.slug if hasattr(instance, 'slug') else None if not slug: return try: httpx.post( settings.NEXTJS_REVALIDATE_URL, json={'slug': slug, 'type': instance.__class__.__name__}, headers={'x-revalidate-secret': settings.NEXTJS_REVALIDATE_SECRET}, timeout=5.0, ) except Exception as e: print(f"Revalidation failed: {e}") page_published.connect(revalidate_page) On the Next.js side, accept the POST request:
// app/api/revalidate/route.ts export async function POST(request: Request) { const { slug, type } = await request.json(); if (type === 'BlogPost') { revalidatePath(`/blog/${slug}`); revalidatePath('/blog'); } return Response.json({ revalidated: true }); } We implemented this solution for an e-commerce store on Wagtail + Next.js. With a load of 50k pages, revalidation time is under 1 second. This scheme saved 40% on infrastructure budget compared to a monolithic solution.
What components does the turnkey Wagtail API setup include?
| Component | Result |
|---|---|
| REST API | All page types, images, documents with custom fields |
| GraphQL API | Full CRUD mutations, subscriptions, auto-documentation |
| Preview | Draft previews via token, integration with Next.js/Vue |
| Webhook revalidation | Automatic cache reset on publish/delete |
| Images | Transformations (renditions) in API response, size optimization |
Additionally: API documentation, CDN integration, load testing. We also audit Core Web Vitals to ensure LCP < 2.5s.
What's included in the work
Turnkey Wagtail API setup includes:
- Development and documentation of REST/GraphQL endpoints.
- Implementation of draft previews.
- Webhook revalidation configuration.
- Integration testing.
- Handover of access and team training.
- Post-release support.
- Access to code repository and deployment scripts.
- Performance optimization and caching setup.
Work process and timeline
Setup stages
1. **Current project audit** — 1 day. 2. **API schema design** — 1 day. 3. **REST/GraphQL implementation** — 2 days. 4. **Preview and webhook integration** — 1 day. 5. **Testing and deployment** — 1 day.Timeline: from 2 to 4 days depending on complexity. Cost is calculated individually — contact us for a project evaluation. Typical projects range from $4,000 to $8,000.
Typical mistakes in headless integration
- CORS not configured — frontend gets no response.
- Forgot
NEXT_PUBLIC_WAGTAIL_URL— environment variables on the client. - Not using
fields=*— extra data in response. - Missing error handling in signals — crash during revalidation.
- Browser cache not disabled — testers see old content.
- Incorrect caching at Django level — slow responses.
- Ignoring LCP and CLS during rendering — poor user experience.
We guarantee stable operation — experience with over 20 headless projects on Wagtail. With 5+ years of expertise, we have a 97% success rate in revalidation setups. Get a consultation on Wagtail API setup today.







