Created comprehensive setup guide for syncing Skool community members to email lists via n8n. Includes browser token extraction guide, n8n workflow template, and configuration examples for multiple email platforms (ConvertKit, Mailchimp, ActiveCampaign, SendGrid). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
12 KiB
Skool + n8n Configuration Reference
VPS: ai-termimal Created: 2025-11-29
Quick Configuration Checklist
Use this as a quick reference when setting up or updating your workflow.
Required Values to Extract from Browser
| Value | Where to Find | Used In | Notes |
|---|---|---|---|
| Cookie | Network > request-bulk-action > Headers > Request Headers | Nodes 2, 3, 4 | Very long string, expires periodically |
| User-Agent | Network > request-bulk-action > Headers > Request Headers | Nodes 2, 3, 4 | Your browser identifier |
| X-AWS-WAF-Token | Network > request-bulk-action > Headers > Request Headers | Nodes 2, 3 | Security token, expires |
| Request Payload | Network > request-bulk-action > Payload | Node 2 | JSON body for export request |
| Expires | Network > Doc > Downloaded file URL | Node 4 | Query parameter for file download |
| Signature | Network > Doc > Downloaded file URL | Node 4 | Query parameter for file download |
| Key-Pair-Id | Network > Doc > Downloaded file URL | Node 4 | Query parameter for file download |
Customization Points
1. Schedule Frequency
Location: Schedule Trigger Node Default: Every 2 hours Customization:
Hours: 1, 2, 4, 6, 12, 24
Minutes: 15, 30, 45, 60
Decision Guide:
- Active community (>10 joins/day): Every 1-2 hours
- Medium activity (3-10 joins/day): Every 4-6 hours
- Low activity (<3 joins/day): Every 12-24 hours
2. Member Limit
Location: Limit Node
Default: 15 members
Formula: (Expected joins/hour × Hours between triggers) × 1.5
Examples:
- If you get 5 members/day and run every 2 hours:
(5/12 × 2) × 1.5 ≈ 2→ Set to 5 (minimum safe) - If you get 50 members/day and run every 2 hours:
(50/12 × 2) × 1.5 ≈ 12→ Set to 15 - If you get 200 members/day and run every 2 hours:
(200/12 × 2) × 1.5 ≈ 50→ Set to 50
Why 1.5x multiplier?: Safety buffer for spikes in signups
3. Email Platform Integration
This is the most variable part of the workflow. Here are examples for popular platforms:
Email Platform Examples
ConvertKit
Search for Subscriber
Node Type: HTTP Request
Method: GET
URL: https://api.convertkit.com/v3/subscribers
Query Parameters:
- api_secret: YOUR_API_SECRET
- email_address: {{ $json.email }}
Response: Returns subscriber if exists, empty if not
Create Subscriber
Node Type: HTTP Request
Method: POST
URL: https://api.convertkit.com/v3/forms/YOUR_FORM_ID/subscribe
Headers:
- Content-Type: application/json
Body:
{
"api_key": "YOUR_API_KEY",
"email": "{{ $json.email }}",
"first_name": "{{ $json.first_name }}",
"tags": ["Skool Member"]
}
Tag Subscriber
Node Type: HTTP Request
Method: POST
URL: https://api.convertkit.com/v3/tags/YOUR_TAG_ID/subscribe
Body:
{
"api_secret": "YOUR_API_SECRET",
"email": "{{ $json.email }}"
}
Mailchimp
Search for Subscriber
Node Type: Mailchimp
Operation: Get Member
Audience ID: YOUR_AUDIENCE_ID
Email: {{ $json.email }}
If exists: Returns member info
If not exists: Returns error (handle with error workflow)
Create Subscriber
Node Type: Mailchimp
Operation: Create or Update Member
Audience ID: YOUR_AUDIENCE_ID
Email: {{ $json.email }}
Status: subscribed
Merge Fields:
FNAME: {{ $json.first_name }}
LNAME: {{ $json.last_name }}
Tags: Skool Member, New Member
ActiveCampaign
Search for Contact
Node Type: ActiveCampaign
Operation: Get Contact
Email: {{ $json.email }}
Create Contact
Node Type: ActiveCampaign
Operation: Create or Update Contact
Email: {{ $json.email }}
First Name: {{ $json.first_name }}
Last Name: {{ $json.last_name }}
Tags: Skool Member
Lists: YOUR_LIST_ID
SendGrid
Search for Contact
Node Type: HTTP Request
Method: POST
URL: https://api.sendgrid.com/v3/marketing/contacts/search
Headers:
- Authorization: Bearer YOUR_API_KEY
- Content-Type: application/json
Body:
{
"query": "email = '{{ $json.email }}'"
}
Create Contact
Node Type: HTTP Request
Method: PUT
URL: https://api.sendgrid.com/v3/marketing/contacts
Headers:
- Authorization: Bearer YOUR_API_KEY
- Content-Type: application/json
Body:
{
"contacts": [
{
"email": "{{ $json.email }}",
"first_name": "{{ $json.first_name }}",
"last_name": "{{ $json.last_name }}"
}
]
}
Generic HTTP Request Template
For any email platform with API access:
Search Pattern
Method: GET or POST
URL: [PLATFORM_API_URL]/search or /subscribers or /contacts
Authentication: API Key / Bearer Token (check platform docs)
Query/Body: { "email": "{{ $json.email }}" }
Create Pattern
Method: POST or PUT
URL: [PLATFORM_API_URL]/create or /subscribe or /add
Authentication: API Key / Bearer Token
Body:
{
"email": "{{ $json.email }}",
"first_name": "{{ $json.first_name }}",
"last_name": "{{ $json.last_name }}",
"tags": ["Skool Member"],
"custom_fields": { ... }
}
CSV Field Mapping
The CSV export from Skool typically contains these fields (may vary):
| Skool Field | Description | Use In Email Platform |
|---|---|---|
| Member's email | Primary identifier | |
| first_name | First name | Personalization |
| last_name | Last name | Personalization |
| joined_at | Join timestamp | Segmentation |
| status | active/inactive | Filter |
| profile_url | Skool profile link | Custom field |
| member_id | Unique ID | Reference |
Access in n8n: {{ $json.field_name }}
Example:
- Email:
{{ $json.email }} - Name:
{{ $json.first_name }} {{ $json.last_name }} - Join Date:
{{ $json.joined_at }}
Advanced Customizations
1. Filter by Join Date
Add a filter node after CSV extraction to only process members who joined in the last X hours:
// In a Function node
const hoursAgo = 2; // Match your schedule frequency
const cutoffTime = new Date(Date.now() - (hoursAgo * 60 * 60 * 1000));
const joinedAt = new Date($json.joined_at);
return joinedAt > cutoffTime;
2. Add Custom Fields
Map Skool data to custom fields in your email platform:
{
"email": "{{ $json.email }}",
"custom_fields": {
"skool_join_date": "{{ $json.joined_at }}",
"skool_profile": "{{ $json.profile_url }}",
"skool_member_id": "{{ $json.member_id }}",
"source": "Skool Community"
}
}
3. Conditional Tagging
Tag members based on Skool data:
// In a Function node before adding to email platform
const tags = ['Skool Member'];
// Check if joined recently (within 24 hours)
const joinedRecently = (Date.now() - new Date($json.joined_at)) < 86400000;
if (joinedRecently) {
tags.push('New Member');
}
// Add to return object
return {
...$json,
tags: tags
};
4. Segment by Activity Level
If your Skool export includes activity data:
// Assuming there's an activity_score field
if ($json.activity_score > 50) {
tags.push('Highly Engaged');
} else if ($json.activity_score > 20) {
tags.push('Moderately Engaged');
} else {
tags.push('Low Engagement');
}
5. Welcome Email Sequences
After adding to email platform, trigger different sequences:
// Based on member type or interests
if ($json.interests && $json.interests.includes('AI')) {
sequenceId = 'AI_WELCOME_SEQUENCE';
} else if ($json.interests && $json.interests.includes('Marketing')) {
sequenceId = 'MARKETING_WELCOME_SEQUENCE';
} else {
sequenceId = 'GENERAL_WELCOME_SEQUENCE';
}
Error Handling
Recommended Error Workflow
Add an "Error Trigger" node to handle failures:
- Error Trigger Node: Catches any workflow errors
- IF Node: Check error type
- Notification Node: Send alert (email, Slack, Discord)
Common Errors:
401 Unauthorized: Tokens expired → Re-extract from browser404 Not Found: URL changed → Check Skool API structure429 Too Many Requests: Rate limited → Reduce frequencyCSV Parse Error: Format changed → Check CSV structure
Error Notification Template
{
"subject": "Skool Sync Error",
"message": "Workflow failed at {{ $json.node }}\nError: {{ $json.error.message }}\nTime: {{ $now }}"
}
Performance Optimization
Reduce n8n Executions
Current Cost (example):
- Runs every 2 hours = 12 executions/day
- Checks 15 members each = 180 checks/day
- With native integrations ≈ 200 operations/day
Optimization:
- Use native nodes when available (count as 1 operation vs HTTP = multiple)
- Increase schedule interval if acceptable latency
- Use conditional logic to skip unnecessary API calls
Batch Processing
For high-volume communities, consider batching:
// Instead of loop, batch add members
const newMembers = $input.all().map(item => ({
email: item.json.email,
first_name: item.json.first_name,
last_name: item.json.last_name
}));
// Send as array to email platform (if supported)
return [{ json: { contacts: newMembers } }];
Security Best Practices
1. Use n8n Credentials
Don't hardcode tokens in nodes:
- Go to Credentials in n8n
- Create new credential for each service
- Select credential in nodes instead of pasting values
2. Environment Variables
For self-hosted n8n, use environment variables:
export SKOOL_COOKIE="your_cookie"
export CONVERTKIT_API_KEY="your_key"
Access in workflow: {{ $env.SKOOL_COOKIE }}
3. Rotate Tokens Regularly
Set a reminder to refresh Skool tokens:
- Weekly for high-security requirements
- Bi-weekly for normal use
- When workflow fails (reactive)
4. Monitor for Unauthorized Access
Check your email platform for:
- Unusual subscription patterns
- Failed authentication attempts
- Unexpected data changes
Testing Checklist
Before activating your workflow:
- Test Schedule Trigger manually
- Verify HTTP Request 1 returns
fileId - Verify HTTP Request 2 returns download URL
- Verify HTTP Request 3 downloads CSV
- Check CSV extraction produces member objects
- Confirm Limit node returns expected count
- Test email platform search (existing member)
- Test email platform create (new member)
- Verify tags are applied correctly
- Check welcome sequence triggers
- Test complete workflow end-to-end
- Monitor first scheduled execution
- Verify no duplicate additions after 24 hours
Maintenance Schedule
Weekly
- Check workflow execution history
- Verify no failed executions
- Spot-check email platform for new members
Monthly
- Review member limit vs actual joins
- Optimize schedule frequency if needed
- Audit email platform for data accuracy
- Update tokens if experiencing auth issues
Quarterly
- Review automation ROI (time saved)
- Consider additional automations
- Update documentation with learnings
Troubleshooting Decision Tree
Workflow Failed?
├─ Authentication Error (401)
│ └─ Re-extract cookies and tokens
├─ No fileId returned
│ └─ Check request payload structure
├─ CSV download failed
│ └─ Re-extract download URL parameters
├─ No new members found
│ └─ Normal if no one joined (check Skool)
├─ Duplicates in email list
│ └─ Check IF node logic (should check existence)
└─ Email platform error
└─ Check API credentials and rate limits
Support Resources
- n8n Community: https://community.n8n.io
- n8n Documentation: https://docs.n8n.io
- Your Email Platform API Docs: [Insert link]
- Original Tutorial: https://www.youtube.com/watch?v=vZaYYzb4y5Y
Version History
- v1.0 (2025-11-29): Initial configuration based on Sant Kala's tutorial
- Document updated for VPS: ai-termimal