AutomationFlowsWeb Scraping › [fc Sub] Browser Sandbox Session

[fc Sub] Browser Sandbox Session

[FC Sub] Browser Sandbox Session. Uses executeWorkflowTrigger, httpRequest, postgres. Event-driven trigger; 7 nodes.

Event trigger★★★★☆ complexity7 nodesExecute Workflow TriggerHTTP RequestPostgres
Web Scraping Trigger: Event Nodes: 7 Complexity: ★★★★☆ Added:

This workflow follows the Execute Workflow Trigger → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "[FC Sub] Browser Sandbox Session",
  "settings": {
    "executionOrder": "v1"
  },
  "nodes": [
    {
      "parameters": {
        "content": "## [FC Sub] Browser Sandbox Session\n**Purpose:** Manage a persistent browser session via Firecrawl `/v1/sandbox/*`. Lets the agent click, scroll, fill forms, and execute JS across multiple turns of the same session \u2014 the only way to handle login-gated or stateful JS-heavy sites.\n\n**Called by:** main agent's `browser_session` tool.\n\n**Actions:**\n- `create` \u2014 opens a new sandbox session, returns `session_id`\n- `execute` \u2014 runs JS (or python/bash) in an existing session, returns stdout/screenshot/page\n- `delete` \u2014 closes a session (always release sessions when done)\n- `list` \u2014 lists active sessions for housekeeping\n\n**Inputs:**\n- `action` (required) \u2014 one of `create`, `execute`, `delete`, `list`\n- `session_id?` \u2014 for execute/delete (required), unused for create/list\n- `code?` \u2014 for execute (required), the snippet to run\n- `language?` \u2014 for execute (default `javascript`)\n- `url?` \u2014 for create (optional starting URL)\n- `session_id_caller?` \u2014 agent chat session id for ledger\n\n**Credit cost:** Session ops are lightweight (~1 credit each). Agent must call `delete` when done \u2014 stale sessions continue to hold browser resources.\n\n**Flow:** Trigger \u2192 Prep (pick endpoint) \u2192 Switch \u2192 HTTP Call \u2192 Shape \u2192 Ledger \u2192 Return.\n\n**Credentials:** Firecrawl API, Postgres RW.",
        "height": 680,
        "width": 620,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -40,
        -720
      ],
      "id": "sticky-fc-sandbox",
      "name": "README"
    },
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        0,
        0
      ],
      "id": "fc-sb-trigger",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst q = (input.query && typeof input.query === 'object') ? input.query : {};\nconst pick = (k, def) => {\n  if (input[k] !== undefined) return input[k];\n  if (q[k] !== undefined) return q[k];\n  return def;\n};\n\nconst action = (pick('action') || '').toString().toLowerCase().trim();\nconst ACTIONS = ['create', 'execute', 'delete', 'list'];\nif (!ACTIONS.includes(action)) {\n  throw new Error(`browser_session.action must be one of: ${ACTIONS.join(', ')}. Got: '${action}'`);\n}\n\nconst sandbox_session = (pick('session_id') || '').toString().trim();\nconst code = (pick('code') || '').toString();\nconst language = ((pick('language') || 'javascript') + '').toLowerCase();\nlet url = (pick('url') || '').toString().trim();\nif (url && !/^https?:\\/\\//i.test(url)) url = 'https://' + url;\n\nif ((action === 'execute' || action === 'delete') && !sandbox_session) {\n  throw new Error(`browser_session.action='${action}' requires session_id (from a prior create call).`);\n}\nif (action === 'execute' && !code.trim()) {\n  throw new Error('browser_session.action=execute requires code.');\n}\n\n// Build the request URL/method based on action\nlet method = 'POST';\nlet api_url = 'https://api.firecrawl.dev/v1/sandbox';\nlet body = null;\n\nswitch (action) {\n  case 'create':\n    api_url = 'https://api.firecrawl.dev/v1/sandbox';\n    method = 'POST';\n    body = url ? { url } : {};\n    break;\n  case 'execute':\n    api_url = `https://api.firecrawl.dev/v1/sandbox/${sandbox_session}/execute`;\n    method = 'POST';\n    body = { code, language };\n    break;\n  case 'delete':\n    api_url = `https://api.firecrawl.dev/v1/sandbox/${sandbox_session}`;\n    method = 'DELETE';\n    body = null;\n    break;\n  case 'list':\n    api_url = 'https://api.firecrawl.dev/v1/sandbox';\n    method = 'GET';\n    body = null;\n    break;\n}\n\nconst caller_session = (pick('session_id_caller') || $execution.id || 'no-session').toString();\n\nreturn [{ json: {\n  action,\n  api_url,\n  method,\n  body,\n  has_body: body !== null,\n  sandbox_session,\n  caller_session,\n  execution_id: $execution.id\n} }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "id": "fc-sb-prep",
      "name": "Prep + Route"
    },
    {
      "parameters": {
        "method": "={{ $json.method }}",
        "url": "={{ $json.api_url }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": "={{ $json.has_body }}",
        "specifyBody": "json",
        "jsonBody": "={{ $json.body ? JSON.stringify($json.body) : '{}' }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          },
          "timeout": 60000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        0
      ],
      "id": "fc-sb-http",
      "name": "Call Firecrawl Sandbox"
    },
    {
      "parameters": {
        "jsCode": "const prep = $('Prep + Route').first().json;\nconst resp = $input.first().json;\n\nlet session_id_out = prep.sandbox_session || null;\nlet output = null;\nlet screenshot = null;\nlet sessions_list = null;\n\nif (prep.action === 'create') {\n  session_id_out = resp.id || resp.sessionId || resp.session_id || null;\n} else if (prep.action === 'execute') {\n  output = resp.output || resp.stdout || resp.result || null;\n  screenshot = resp.screenshot || null;\n} else if (prep.action === 'list') {\n  sessions_list = Array.isArray(resp.sessions) ? resp.sessions\n               : Array.isArray(resp.data) ? resp.data\n               : [];\n}\n\nconst credits_used = prep.action === 'list' ? 0 : 1;\n\nreturn [{ json: {\n  action: prep.action,\n  session_id: session_id_out,\n  output,\n  screenshot,\n  sessions: sessions_list,\n  raw: resp,\n  credits_used,\n  caller_session: prep.caller_session,\n  execution_id: prep.execution_id\n} }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        0
      ],
      "id": "fc-sb-shape",
      "name": "Shape Response"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO public.firecrawl_credit_ledger (session_id, execution_id, operation, credits_used, status, metadata)\nVALUES ($1, $2, $3, $4, 'ok', $5::jsonb);",
        "options": {
          "queryReplacement": "={{ $json.caller_session }}, {{ $json.execution_id }}, {{ 'sandbox_' + $json.action }}, {{ $json.credits_used }}, {{ JSON.stringify({ sandbox_session_id: $json.session_id }) }}"
        }
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        880,
        0
      ],
      "id": "fc-sb-ledger",
      "name": "Log Credit Ledger"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "sb1",
              "name": "action",
              "value": "={{ $('Shape Response').first().json.action }}",
              "type": "string"
            },
            {
              "id": "sb2",
              "name": "session_id",
              "value": "={{ $('Shape Response').first().json.session_id }}",
              "type": "string"
            },
            {
              "id": "sb3",
              "name": "output",
              "value": "={{ $('Shape Response').first().json.output }}",
              "type": "string"
            },
            {
              "id": "sb4",
              "name": "screenshot",
              "value": "={{ $('Shape Response').first().json.screenshot }}",
              "type": "string"
            },
            {
              "id": "sb5",
              "name": "sessions",
              "value": "={{ $('Shape Response').first().json.sessions }}",
              "type": "array"
            },
            {
              "id": "sb6",
              "name": "credits_used",
              "value": "={{ $('Shape Response').first().json.credits_used }}",
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1100,
        0
      ],
      "id": "fc-sb-return",
      "name": "Return Sandbox"
    }
  ],
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Prep + Route",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prep + Route": {
      "main": [
        [
          {
            "node": "Call Firecrawl Sandbox",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Firecrawl Sandbox": {
      "main": [
        [
          {
            "node": "Shape Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Shape Response": {
      "main": [
        [
          {
            "node": "Log Credit Ledger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Credit Ledger": {
      "main": [
        [
          {
            "node": "Return Sandbox",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

[FC Sub] Browser Sandbox Session. Uses executeWorkflowTrigger, httpRequest, postgres. Event-driven trigger; 7 nodes.

Source: https://github.com/MinaSaad1/n8n-firecrawl-web-crawler-agent/blob/main/workflows/10-sub-browser-sandbox.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

[FC Sub] Scrape URL with 24h Cache. Uses executeWorkflowTrigger, postgres, httpRequest. Event-driven trigger; 14 nodes.

Execute Workflow Trigger, Postgres, HTTP Request
Web Scraping

[FC Sub] Crawl Site (Bounded). Uses executeWorkflowTrigger, httpRequest, postgres. Event-driven trigger; 12 nodes.

Execute Workflow Trigger, HTTP Request, Postgres
Web Scraping

[FC Sub] Batch Scrape URLs. Uses executeWorkflowTrigger, httpRequest, postgres. Event-driven trigger; 12 nodes.

Execute Workflow Trigger, HTTP Request, Postgres
Web Scraping

[FC Sub] Extract Structured Data. Uses executeWorkflowTrigger, httpRequest, postgres. Event-driven trigger; 12 nodes.

Execute Workflow Trigger, HTTP Request, Postgres
Web Scraping

[FC Sub] Search the Web. Uses executeWorkflowTrigger, httpRequest, postgres. Event-driven trigger; 7 nodes.

Execute Workflow Trigger, HTTP Request, Postgres