agentsclimarketplace

Webflow multi env setup

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/webflow-pack/skills/webflow-multi-env-setup

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill webflow-multi-env-setup

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

'Configure Webflow across development, staging, and production environments with

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

9.4 KB, as published. Nobody here has run it

Webflow Multi-Environment Setup

Overview

Configure Webflow Data API v2 integrations across development, staging, and production with separate API tokens, site IDs, and secret management. Each environment targets a different Webflow site for complete isolation.

Prerequisites

  • Separate Webflow sites for each environment (or at minimum, separate API tokens)
  • Secret management solution (Vault, AWS Secrets Manager, or GCP Secret Manager)
  • CI/CD pipeline with environment variable support

Environment Strategy

EnvironmentWebflow SiteAPI TokenCMS DataPurpose
DevelopmentDev siteDev tokenTest/seed dataLocal development
StagingStaging siteStaging tokenCopy of prod dataPre-prod validation
ProductionProduction siteProd tokenReal dataLive traffic

Instructions

Step 1: Environment Configuration

// src/config/webflow.ts
type Environment = "development" | "staging" | "production";

interface WebflowEnvConfig {
  accessToken: string;
  siteId: string;
  maxRetries: number;
  webhookSecret: string;
  debug: boolean;
}

function detectEnvironment(): Environment {
  const env = process.env.NODE_ENV || "development";
  const valid: Environment[] = ["development", "staging", "production"];
  return valid.includes(env as Environment) ? (env as Environment) : "development";
}

export function getWebflowConfig(): WebflowEnvConfig {
  const env = detectEnvironment();

  // Each environment has its own token and site
  const configs: Record<Environment, () => WebflowEnvConfig> = {
    development: () => ({
      accessToken: requireEnv("WEBFLOW_API_TOKEN"),
      siteId: requireEnv("WEBFLOW_SITE_ID"),
      maxRetries: 1,
      webhookSecret: process.env.WEBFLOW_WEBHOOK_SECRET || "",
      debug: true,
    }),
    staging: () => ({
      accessToken: requireEnv("WEBFLOW_API_TOKEN_STAGING"),
      siteId: requireEnv("WEBFLOW_SITE_ID_STAGING"),
      maxRetries: 2,
      webhookSecret: requireEnv("WEBFLOW_WEBHOOK_SECRET_STAGING"),
      debug: false,
    }),
    production: () => ({
      accessToken: requireEnv("WEBFLOW_API_TOKEN_PROD"),
      siteId: requireEnv("WEBFLOW_SITE_ID_PROD"),
      maxRetries: 3,
      webhookSecret: requireEnv("WEBFLOW_WEBHOOK_SECRET_PROD"),
      debug: false,
    }),
  };

  const config = configs[env]();
  console.log(`[webflow] Environment: ${env}, Site: ${config.siteId.substring(0, 8)}...`);
  return config;
}

function requireEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required env var: ${name}`);
  return value;
}

Step 2: Environment Files

# .env.development (local, git-ignored)
WEBFLOW_API_TOKEN=dev-token-here
WEBFLOW_SITE_ID=dev-site-id-here
WEBFLOW_WEBHOOK_SECRET=dev-webhook-secret

# .env.staging (stored in CI/deployment platform, never committed)
WEBFLOW_API_TOKEN_STAGING=staging-token-here
WEBFLOW_SITE_ID_STAGING=staging-site-id-here
WEBFLOW_WEBHOOK_SECRET_STAGING=staging-webhook-secret

# .env.production (stored in vault/secret manager, never committed)
WEBFLOW_API_TOKEN_PROD=prod-token-here
WEBFLOW_SITE_ID_PROD=prod-site-id-here
WEBFLOW_WEBHOOK_SECRET_PROD=prod-webhook-secret

# .env.example (committed to repo, no real values)
WEBFLOW_API_TOKEN=your-token-here
WEBFLOW_SITE_ID=your-site-id-here
WEBFLOW_WEBHOOK_SECRET=your-webhook-secret

Step 3: Secret Management

AWS Secrets Manager

# Store secrets
aws secretsmanager create-secret \
  --name webflow/production \
  --secret-string '{
    "WEBFLOW_API_TOKEN": "prod-token",
    "WEBFLOW_SITE_ID": "prod-site-id",
    "WEBFLOW_WEBHOOK_SECRET": "prod-webhook-secret"
  }'

# Retrieve in application
aws secretsmanager get-secret-value \
  --secret-id webflow/production \
  --query SecretString --output text | jq .
// Load from AWS at startup
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";

async function loadWebflowSecrets(env: string) {
  const client = new SecretsManagerClient({});
  const command = new GetSecretValueCommand({
    SecretId: `webflow/${env}`,
  });
  const response = await client.send(command);
  const secrets = JSON.parse(response.SecretString!);

  process.env.WEBFLOW_API_TOKEN_PROD = secrets.WEBFLOW_API_TOKEN;
  process.env.WEBFLOW_SITE_ID_PROD = secrets.WEBFLOW_SITE_ID;
}

GCP Secret Manager

# Store secrets
echo -n "prod-token" | gcloud secrets create webflow-api-token-prod --data-file=-
echo -n "prod-site-id" | gcloud secrets create webflow-site-id-prod --data-file=-

# Use in Cloud Run
gcloud run deploy webflow-service \
  --set-secrets="WEBFLOW_API_TOKEN_PROD=webflow-api-token-prod:latest,WEBFLOW_SITE_ID_PROD=webflow-site-id-prod:latest"

HashiCorp Vault

# Store secrets
vault kv put secret/webflow/production \
  api_token="prod-token" \
  site_id="prod-site-id" \
  webhook_secret="prod-webhook-secret"

# Retrieve
vault kv get -field=api_token secret/webflow/production

Step 4: Environment Guards

Prevent destructive operations in wrong environment:

function requireProduction(operation: string): void {
  const config = getWebflowConfig();
  if (config.debug) {
    throw new Error(
      `${operation} is production-only. Current: ${detectEnvironment()}`
    );
  }
}

function blockProduction(operation: string): void {
  const env = detectEnvironment();
  if (env === "production") {
    throw new Error(
      `${operation} is blocked in production. Use staging for testing.`
    );
  }
}

// Usage
async function publishSite(siteId: string) {
  requireProduction("publishSite"); // Only in production
  await webflow.sites.publish(siteId, { publishToWebflowSubdomain: true });
}

async function deleteAllItems(collectionId: string) {
  blockProduction("deleteAllItems"); // Never in production
  const { items } = await webflow.collections.items.listItems(collectionId);
  const ids = items!.map(i => i.id!);
  await webflow.collections.items.deleteItemsBulk(collectionId, { itemIds: ids });
}

Step 5: CI/CD Environment Matrix

# .github/workflows/webflow-deploy.yml
name: Deploy Webflow Integration

on:
  push:
    branches: [main, staging]

jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - branch: staging
            env: staging
            token_secret: WEBFLOW_API_TOKEN_STAGING
            site_secret: WEBFLOW_SITE_ID_STAGING
          - branch: main
            env: production
            token_secret: WEBFLOW_API_TOKEN_PROD
            site_secret: WEBFLOW_SITE_ID_PROD

    if: github.ref == format('refs/heads/{0}', matrix.branch)
    environment: ${{ matrix.env }}
    env:
      NODE_ENV: ${{ matrix.env }}
      WEBFLOW_API_TOKEN: ${{ secrets[matrix.token_secret] }}
      WEBFLOW_SITE_ID: ${{ secrets[matrix.site_secret] }}

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
      - run: npm ci
      - run: npm test
      - name: Verify Webflow connectivity
        run: |
          curl -sf -H "Authorization: Bearer $WEBFLOW_API_TOKEN" \
            https://api.webflow.com/v2/sites/$WEBFLOW_SITE_ID > /dev/null
      - run: npm run deploy

Step 6: Environment Status Dashboard

async function environmentReport() {
  for (const env of ["development", "staging", "production"]) {
    try {
      process.env.NODE_ENV = env;
      const config = getWebflowConfig();
      const webflow = new WebflowClient({ accessToken: config.accessToken });

      const site = await webflow.sites.get(config.siteId);
      console.log(`[${env}] ${site.displayName} — last published: ${site.lastPublished}`);
    } catch (error: any) {
      console.log(`[${env}] ERROR: ${error.message}`);
    }
  }
}

Output

  • Per-environment configuration with separate tokens and site IDs
  • Secret management via AWS/GCP/Vault
  • Environment guards preventing dangerous cross-environment operations
  • CI/CD matrix deploying to correct environment per branch
  • Environment status reporting

Error Handling

IssueCauseSolution
Wrong site in productionToken/site mismatchVerify WEBFLOW_SITE_ID matches expected site
Secret not foundWrong path/nameCheck secret manager path matches env
Guard triggeredRunning prod operation in devSet NODE_ENV correctly
Missing env var.env not loadeddotenv.config({ path: ".env.development" })

Resources

Next Steps

For observability setup, see webflow-observability.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.