Webflow CI Integration
Overview
Set up CI/CD pipelines for Webflow Data API v2 integrations with GitHub Actions.
Includes unit tests with mocked SDK, integration tests with test tokens, CMS schema
validation, and automated publish-on-merge workflows.
Prerequisites
- GitHub repository with Actions enabled
- Webflow API token (test environment) stored as GitHub secret
webflow-api SDK with vitest test suite
Instructions
Step 1: Store Secrets
gh secret set WEBFLOW_API_TOKEN --body "your-test-token"
gh secret set WEBFLOW_SITE_ID --body "your-test-site-id"
gh secret set WEBFLOW_API_TOKEN_PROD --body "your-prod-token"
Step 2: Unit Test Workflow
Tests that mock the SDK — run on every PR, no API calls:
name: Webflow Integration Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm test -- --coverage
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
lint-and-typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npx tsc --noEmit
- run: npm run lint
Step 3: Integration Test Workflow
Tests against the real Webflow API — run only on main branch with secrets:
name: Webflow Integration Tests
on:
push:
branches: [main]
workflow_dispatch:
jobs:
integration:
runs-on: ubuntu-latest
if: ${{ vars.WEBFLOW_TESTS_ENABLED == 'true' }}
env:
WEBFLOW_API_TOKEN: ${{ secrets.WEBFLOW_API_TOKEN }}
WEBFLOW_SITE_ID: ${{ secrets.WEBFLOW_SITE_ID }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Verify Webflow connectivity
run: |
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
https://api.webflow.com/v2/sites)
if [ "$HTTP_CODE" != "200" ]; then
echo "Webflow API returned HTTP $HTTP_CODE"
exit 1
fi
Step 4: Integration Test Example
import { describe, it, expect } from "vitest";
import { WebflowClient } from "webflow-api";
const SKIP = !process.env.WEBFLOW_API_TOKEN;
describe.skipIf(SKIP)("Webflow API Integration", () => {
const webflow = new WebflowClient({
accessToken: process.env.WEBFLOW_API_TOKEN!,
});
const siteId = process.env.WEBFLOW_SITE_ID!;
it("should list sites", async () => {
const { sites } = await webflow.sites.list();
expect(sites).toBeDefined();
expect(sites!.length).toBeGreaterThan(0);
});
it("should get site details", async () => {
const site = await webflow.sites.get(siteId);
expect(site.id).toBe(siteId);
expect(site.).();
});
(, () => {
{ collections } = webflow..(siteId);
(collections).();
( col collections!) {
(col.).();
(col.).();
(col.).();
}
});
(, () => {
promises = .({ : },
webflow..()
);
results = .(promises);
(results.( r.!. > )).();
});
});
Step 5: CMS Schema Validation
Ensure your code matches the live Webflow collection schema:
import { describe, it, expect } from "vitest";
import { WebflowClient } from "webflow-api";
const SKIP = !process.env.WEBFLOW_API_TOKEN;
describe.skipIf(SKIP)("CMS Schema Validation", () => {
const webflow = new WebflowClient({
accessToken: process.env.WEBFLOW_API_TOKEN!,
});
const siteId = process.env.WEBFLOW_SITE_ID!;
const EXPECTED_FIELDS = [
{ slug: "name", type: "PlainText", required: true },
{ slug: "slug", type: "PlainText", required: true },
{ slug: "post-body", type: "RichText", required: false },
{ slug: "author-name", type: "PlainText", required: },
{ : , : , : },
];
(, () => {
{ collections } = webflow..(siteId);
blogCollection = collections!.( c. === );
(blogCollection).();
( expected ) {
field = blogCollection!.!.( f. === expected.);
(field, ).();
(field!.).(expected.);
}
});
});
Step 6: Publish-on-Merge Workflow
Automatically publish Webflow site when content changes merge to main:
name: Publish Webflow Site
on:
push:
branches: [main]
paths:
- "content/**"
- "src/webflow/**"
jobs:
sync-and-publish:
runs-on: ubuntu-latest
env:
WEBFLOW_API_TOKEN: ${{ secrets.WEBFLOW_API_TOKEN_PROD }}
WEBFLOW_SITE_ID: ${{ secrets.WEBFLOW_SITE_ID_PROD }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Sync content to Webflow CMS
run: npm run sync:webflow
-
Output
- Unit test pipeline (mocked, runs on every PR)
- Integration test pipeline (real API, runs on main)
- CMS schema validation tests
- Automated publish-on-merge workflow
- GitHub secrets configured
Error Handling
| Issue | Cause | Solution |
|---|
| Secret not found | Missing gh secret set | Add secret via GitHub CLI |
| Integration tests timeout | Rate limited or slow API | Increase timeout, reduce parallelism |
| Schema mismatch | Collection changed in Webflow | Update expected schema in tests |
| Publish fails in CI | Wrong production token | Verify WEBFLOW_API_TOKEN_PROD secret |
Resources
Next Steps
For deployment patterns, see webflow-deploy-integration.