CI/CD Integration
Catch design drift before it ships by integrating StyleGrab into your deployment pipeline.
Overview
Add StyleGrab checks to your CI/CD pipeline to:
- Compare staging against production before deploying
- Fail builds when unexpected design changes are detected
- Generate design diff reports on pull requests
GitHub Actions
Basic Check
# .github/workflows/design-check.yml
name: Design Check
on:
pull_request:
branches: [main]
jobs:
design-diff:
runs-on: ubuntu-latest
steps:
- name: Extract from Preview
id: preview
run: |
RESPONSE=$(curl -s -X POST https://api.stylegrab.dev/api/extractions \
-H "Authorization: Bearer ${{ secrets.STYLEGRAB_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"url": "${{ env.PREVIEW_URL }}"}')
echo "extraction_id=$(echo $RESPONSE | jq -r '.id')" >> $GITHUB_OUTPUT
- name: Wait for Extraction
run: sleep 15
- name: Compare with Production
id: diff
run: |
# Get preview snapshot
PREVIEW_SNAP=$(curl -s "https://api.stylegrab.dev/api/extractions/${{ steps.preview.outputs.extraction_id }}/snapshots" \
-H "Authorization: Bearer ${{ secrets.STYLEGRAB_API_KEY }}" | jq -r '.data[0].id')
# Compare against production baseline
DIFF=$(curl -s "https://api.stylegrab.dev/api/extractions/${{ steps.preview.outputs.extraction_id }}/diff?from=${{ vars.PROD_BASELINE_SNAP }}&to=$PREVIEW_SNAP" \
-H "Authorization: Bearer ${{ secrets.STYLEGRAB_API_KEY }}")
TOTAL_CHANGES=$(echo $DIFF | jq '.summary.total_changes')
echo "changes=$TOTAL_CHANGES" >> $GITHUB_OUTPUT
echo "$DIFF" > diff.json
- name: Comment on PR
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const diff = JSON.parse(fs.readFileSync('diff.json', 'utf8'));
let body = '## 🎨 Design Token Changes\n\n';
if (diff.summary.total_changes === 0) {
body += '✅ No design token changes detected.';
} else {
body += `⚠️ **${diff.summary.total_changes} changes detected**\n\n`;
body += `| Type | Changes |\n|------|--------|\n`;
body += `| Colors | ${diff.summary.colors_changed} |\n`;
body += `| Typography | ${diff.summary.typography_changed} |\n`;
body += `| Spacing | ${diff.summary.spacing_changed} |\n`;
}
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
- name: Fail on Unexpected Changes
if: steps.diff.outputs.changes > 5
run: |
echo "Too many design changes detected (${{ steps.diff.outputs.changes }})"
exit 1
Required Secrets
Add these to your repository settings:
STYLEGRAB_API_KEY— Your API keyPROD_BASELINE_SNAP— Snapshot ID of your production baseline
GitLab CI
# .gitlab-ci.yml
design-check:
stage: test
image: curlimages/curl:latest
script:
- |
# Start extraction
EXTRACTION=$(curl -s -X POST https://api.stylegrab.dev/api/extractions \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" \
-d "{\"url\": \"$CI_ENVIRONMENT_URL\"}")
EXTRACTION_ID=$(echo $EXTRACTION | jq -r '.id')
# Wait and get snapshot
sleep 15
SNAPSHOT=$(curl -s "https://api.stylegrab.dev/api/extractions/$EXTRACTION_ID/snapshots" \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" | jq -r '.data[0].id')
# Compare
DIFF=$(curl -s "https://api.stylegrab.dev/api/extractions/$EXTRACTION_ID/diff?from=$PROD_BASELINE&to=$SNAPSHOT" \
-H "Authorization: Bearer $STYLEGRAB_API_KEY")
CHANGES=$(echo $DIFF | jq '.summary.total_changes')
echo "Design changes detected: $CHANGES"
if [ "$CHANGES" -gt 5 ]; then
echo "Too many design changes. Failing pipeline."
exit 1
fi
only:
- merge_requests
CircleCI
# .circleci/config.yml
version: 2.1
jobs:
design-check:
docker:
- image: cimg/base:stable
steps:
- run:
name: Check Design Tokens
command: |
RESPONSE=$(curl -s -X POST https://api.stylegrab.dev/api/extractions \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" \
-d '{"url": "'$PREVIEW_URL'"}')
EXTRACTION_ID=$(echo $RESPONSE | jq -r '.id')
sleep 15
SNAPSHOT=$(curl -s "https://api.stylegrab.dev/api/extractions/$EXTRACTION_ID/snapshots" \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" | jq -r '.data[0].id')
CHANGES=$(curl -s "https://api.stylegrab.dev/api/extractions/$EXTRACTION_ID/diff?from=$PROD_BASELINE&to=$SNAPSHOT" \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" | jq '.summary.total_changes')
echo "Changes: $CHANGES"
[ "$CHANGES" -le 5 ] || exit 1
workflows:
version: 2
test:
jobs:
- design-check
Best Practices
1. Use Preview Environments
Always compare against a preview/staging URL, not localhost:
env:
PREVIEW_URL: https://preview-${{ github.event.pull_request.number }}.yoursite.dev
2. Set Reasonable Thresholds
Start permissive and tighten over time:
- Warning: > 3 changes
- Failure: > 10 changes
3. Allow Intentional Changes
Add labels to bypass checks for intentional design updates:
- name: Check for Skip Label
if: contains(github.event.pull_request.labels.*.name, 'design-update')
run: echo "Skipping design check - intentional update"
4. Update Baseline After Deploys
# Post-deploy job
update-baseline:
needs: deploy
steps:
- run: |
EXTRACTION=$(curl -s -X POST https://api.stylegrab.dev/api/extractions \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" \
-d '{"url": "https://yoursite.com"}')
sleep 15
SNAPSHOT=$(curl -s "https://api.stylegrab.dev/api/extractions/$(echo $EXTRACTION | jq -r '.id')/snapshots" \
-H "Authorization: Bearer $STYLEGRAB_API_KEY" | jq -r '.data[0].id')
# Store as new baseline
gh variable set PROD_BASELINE_SNAP --body "$SNAPSHOT"
Troubleshooting
Extraction timing out
Increase the wait time or use webhooks instead of polling:
- name: Wait for Webhook
uses: lewagon/wait-on-check-action@v1.3.4
with:
ref: ${{ github.ref }}
check-name: 'stylegrab-extraction'
wait-interval: 10
Flaky diffs
Some sites have dynamic content. Use selectors to target stable areas:
curl -X POST https://api.stylegrab.dev/api/extractions \
-d '{
"url": "https://yoursite.com",
"options": {
"selectors": ["#main-content", ".design-system-components"],
"exclude_selectors": [".ad-banner", ".dynamic-promo"]
}
}'
Next Steps
- Webhook setup for async processing
- Design drift monitoring for ongoing tracking