Skip to main content

Xano Integration

Overview

This guide shows you how to integrate SpiderIQ's orchestrated campaigns with Xano, a no-code backend platform. You'll build a complete lead generation system that:

  1. Creates orchestrated campaigns via SpiderIQ API
  2. Processes locations automatically with workflow chaining
  3. Stores enriched leads in your Xano database
  4. Schedules recurring campaigns with Xano Tasks

Prerequisites

👤

Xano Account

Free tier works for testing. Pro tier recommended for production.

🔑

SpiderIQ Credentials

Your API token from SpiderIQ dashboard.

Step 1: Store API Credentials

First, securely store your SpiderIQ API token in Xano's environment variables.

Open Xano Settings

Navigate to your Xano workspace → Settings → Environment Variables

Add SpiderIQ Token

Create a new variable:

  • Name: SPIDERIQ_TOKEN
  • Value: Your SpiderIQ API token (e.g., cli_xxx:sk_xxx:secret_xxx)
  • Environment: Production (and optionally Development)
Save Changes

Click Save. This token is now accessible in all Function Stacks.

warning

Never hardcode API tokens in Function Stacks. Always use environment variables for security.

Step 2: Create Database Tables

Create three tables to store campaign data and leads.

Table: campaigns

FieldTypeDescription
idInteger (Auto)Primary key
campaign_idTextSpiderIQ campaign ID
queryTextSearch query (e.g., "restaurants")
country_codeTextISO country code
statusTextCampaign status
total_locationsIntegerNumber of locations
has_workflowBooleanWorkflow enabled
created_atTimestampCreation time
completed_atTimestampCompletion time

Table: leads

FieldTypeDescription
idInteger (Auto)Primary key
campaign_idTextForeign key to campaigns
business_nameTextBusiness name
business_addressTextFull address
business_phoneTextPhone number
business_ratingDecimalGoogle rating
domainTextWebsite domain
locationTextCity/location name
workflow_stageTextCurrent stage
created_atTimestampCreation time

Table: lead_emails

FieldTypeDescription
idInteger (Auto)Primary key
lead_idIntegerForeign key to leads
emailTextEmail address
statusTextvalid, invalid, risky, unknown
scoreIntegerDeliverability score (0-100)
is_deliverableBooleanIs deliverable
is_role_accountBooleanIs role account (info@, etc.)
tip

Add indexes on campaign_id fields for better query performance when processing large campaigns.

Step 3: Create Campaign Function Stack

Build a Function Stack to create orchestrated campaigns.

Function Stack: create_campaign

Input Parameters:

  • query (Text, required) - Search query
  • country_code (Text, required) - ISO country code
  • min_population (Integer, optional) - Minimum city population
Step-by-Step Configuration

Node 1: Build Request Body

  • Type: Create Variable
  • Name: request_body
  • Value (Object):
{
"query": "$input.query",
"country_code": "$input.country_code",
"filter": {
"mode": "population",
"min_population": "$input.min_population"
},
"workflow": {
"spidersite": {
"enabled": true,
"max_pages": 10,
"extract_company_info": true
},
"spiderverify": {
"enabled": true,
"max_emails_per_business": 5
},
"filter_social_media": true,
"filter_review_sites": true
}
}

Node 2: HTTP Request

  • Type: External API Request
  • Method: POST
  • URL: https://spideriq.ai/api/v1/jobs/spiderMaps/campaigns/submit
  • Headers:
    • Authorization: Bearer $env.SPIDERIQ_TOKEN
    • Content-Type: application/json
  • Body: $var.request_body

Node 3: Store Campaign

  • Type: Add Record (campaigns table)
  • Fields:
    • campaign_id: $external.campaign_id
    • query: $input.query
    • country_code: $input.country_code
    • status: $external.status
    • total_locations: $external.total_locations
    • has_workflow: $external.has_workflow
    • created_at: now()

Node 4: Return Response

  • Type: Return
  • Value: $external (full SpiderIQ response)

Example Response

{
"campaign_id": "camp_fr_restaurants_20251223_abc123",
"status": "active",
"total_locations": 42,
"has_workflow": true
}

Step 4: Process Campaign Loop

Create a Function Stack that processes all locations in a campaign.

Function Stack: process_campaign

Input Parameters:

  • campaign_id (Text, required) - The SpiderIQ campaign ID
Step-by-Step Configuration

Node 1: Initialize Loop Variable

  • Type: Create Variable
  • Name: has_more
  • Value: true

Node 2: While Loop

  • Type: Loop (While)
  • Condition: $var.has_more == true

Inside Loop:

Node 2.1: Call /next Endpoint

  • Type: External API Request
  • Method: POST
  • URL: https://spideriq.ai/api/v1/jobs/spiderMaps/campaigns/$input.campaign_id/next
  • Headers:
    • Authorization: Bearer $env.SPIDERIQ_TOKEN

Node 2.2: Update has_more

  • Type: Update Variable
  • Name: has_more
  • Value: $external.has_more

Node 2.3: Conditional (if current_task exists)

  • Type: Conditional
  • Condition: $external.current_task != null

Node 2.3.1: Log Progress (inside conditional)

  • Type: Create Variable
  • Name: progress_log
  • Value: Processing: $external.current_task.search_string

Node 2.4: Wait (Rate Limiting)

  • Type: Utilities → Wait
  • Duration: 2 seconds

End Loop

Node 3: Update Campaign Status

  • Type: Edit Record (campaigns table)
  • Filter: campaign_id == $input.campaign_id
  • Fields:
    • status: completed
    • completed_at: now()

Node 4: Return

  • Type: Return
  • Value: { "status": "completed", "campaign_id": "$input.campaign_id" }
warning

Rate Limiting: Include a 1-2 second delay between /next calls to avoid overwhelming the API. SpiderIQ processes jobs asynchronously, so there's no need to rush.

Step 5: Get and Store Results

After the campaign completes, fetch and store the aggregated results.

Function Stack: get_campaign_results

Input Parameters:

  • campaign_id (Text, required) - The SpiderIQ campaign ID
Step-by-Step Configuration

Node 1: Fetch Workflow Results

  • Type: External API Request
  • Method: GET
  • URL: https://spideriq.ai/api/v1/jobs/spiderMaps/campaigns/$input.campaign_id/workflow-results
  • Headers:
    • Authorization: Bearer $env.SPIDERIQ_TOKEN

Node 2: Loop Through Locations

  • Type: Loop (For Each)
  • Array: $external.locations
  • Item Variable: location

Node 2.1: Loop Through Businesses

  • Type: Loop (For Each)
  • Array: $var.location.businesses
  • Item Variable: business

Node 2.1.1: Add Lead Record

  • Type: Add Record (leads table)
  • Fields:
    • campaign_id: $input.campaign_id
    • business_name: $var.business.business_name
    • business_address: $var.business.business_address
    • business_phone: $var.business.business_phone
    • business_rating: $var.business.business_rating
    • domain: $var.business.domain
    • location: $var.location.display_name
    • workflow_stage: $var.business.workflow_stage
    • created_at: now()

Node 2.1.2: Get Lead ID

  • Type: Create Variable
  • Name: lead_id
  • Value: $addrecord.id

Node 2.1.3: Loop Through Verified Emails

  • Type: Loop (For Each)
  • Array: $var.business.emails_verified
  • Item Variable: email
  • Condition: $var.email.status == "valid"

Node 2.1.3.1: Add Email Record

  • Type: Add Record (lead_emails table)
  • Fields:
    • lead_id: $var.lead_id
    • email: $var.email.email
    • status: $var.email.status
    • score: $var.email.score
    • is_deliverable: $var.email.is_deliverable
    • is_role_account: $var.email.is_role_account

End All Loops

Node 3: Return Summary

  • Type: Return
  • Value:
{
"campaign_id": "$input.campaign_id",
"total_businesses": "$external.total_businesses",
"total_valid_emails": "$external.total_valid_emails"
}

Step 6: Schedule with Xano Tasks

Automate your lead generation with scheduled tasks.

Create a Scheduled Task

Navigate to Tasks

Go to your Xano workspace → Background Tasks

Create New Task

Click "Add Task" and configure:

  • Name: daily_lead_campaign
  • Schedule: Cron expression (e.g., 0 8 * * * for 8 AM daily)
Configure Task Logic

Build a Function Stack that:

  1. Creates a new campaign with today's parameters
  2. Calls process_campaign to iterate locations
  3. Calls get_campaign_results to store leads
  4. Optionally sends notification (email, Slack webhook)

Complete Scheduled Task Function Stack

1. Create Campaign
→ Call: create_campaign(query: "restaurants", country_code: "US", min_population: 50000)
→ Store campaign_id

2. Process All Locations
→ Call: process_campaign(campaign_id: $step1.campaign_id)
→ Wait for completion

3. Fetch and Store Results
→ Call: get_campaign_results(campaign_id: $step1.campaign_id)

4. Send Notification (Optional)
→ External API Request to Slack/Email
→ Include: total_businesses, total_valid_emails

Step 7: Build a Dashboard API

Create endpoints for your frontend to display campaign progress.

Endpoint: GET /campaigns

Returns all campaigns with progress stats.

// Response
[
{
"campaign_id": "camp_fr_restaurants_20251223_abc123",
"query": "restaurants",
"country_code": "FR",
"status": "completed",
"total_locations": 42,
"leads_count": 840,
"valid_emails_count": 892,
"created_at": "2025-12-23T10:30:00Z"
}
]

Endpoint: GET /campaigns/{id}/leads

Returns leads for a specific campaign with filtering.

Query Parameters:

  • min_rating - Filter by minimum Google rating
  • has_email - Only leads with valid emails
  • page, page_size - Pagination
// Response
{
"leads": [
{
"business_name": "Le Petit Bistro",
"business_address": "123 Rue de Rivoli, Paris",
"business_rating": 4.5,
"domain": "lepetitbistro.fr",
"emails": [
{"email": "contact@lepetitbistro.fr", "status": "valid", "score": 95}
]
}
],
"total": 840,
"page": 1
}

Complete Xano Workflow

Here's the complete automated flow:

Error Handling

Add error handling to your Function Stacks:

API Error Handling

After each External API Request, add a Conditional:

Condition: $external.statusCode >= 400

If True:
→ Log Error: "SpiderIQ API Error: $external.statusCode"
→ Update campaign status to "error"
→ Stop execution / Return error
Retry Logic

For transient failures, implement retry:

1. Create Variable: retry_count = 0
2. While retry_count < 3:
→ Try API call
→ If success: break
→ If fail: retry_count++, wait 5 seconds
3. If still failing: log and alert

Best Practices

📚

Batch Processing

For large countries, split into regional campaigns to avoid timeouts.

⏱️

Rate Limiting

Add 1-2 second delays between API calls. SpiderIQ queues jobs asynchronously.

🗄️

Incremental Storage

Store leads as they come in via /next responses, not just at the end.

📈

Monitoring

Log campaign progress and set up alerts for failures.

SpiderMedia Integration

SpiderMedia provides per-client file and video storage. Use the base64 endpoint for file uploads in Xano.

warning

Xano doesn't support multipart/form-data natively. Always use the base64 endpoint for file uploads.

Upload Files (Images, Documents)

Use /media/files/upload-base64 with JSON:

SettingValue
MethodPOST
URLhttps://spideriq.ai/api/v1/media/files/upload-base64
HeadersAuthorization: Bearer $env.SPIDERIQ_TOKEN
HeadersContent-Type: application/json

Body:

{
"file_data": "{base64_encoded_content}",
"filename": "logo.png",
"folder": "uploads"
}
tip

Use Xano's base64_encode() function to encode file content before sending.

Import Videos (from URL)

Video import uses standard JSON - no base64 needed:

SettingValue
MethodPOST
URLhttps://spideriq.ai/api/v1/media/videos/import
HeadersAuthorization: Bearer $env.SPIDERIQ_TOKEN
HeadersContent-Type: application/json

Body:

{
"url": "https://instagram.com/reel/ABC123",
"title": "Product Demo",
"privacy": 2
}

Poll Video Status

After importing, poll until status is ready:

SettingValue
MethodGET
URLhttps://spideriq.ai/api/v1/media/videos/{video_id}/status

When status === "ready", the response includes:

  • file_url - Direct .mp4 URL for downloading
  • download_url - Download endpoint URL

See the SpiderMedia Storage Guide for complete examples.

Next Steps