AutomationFlowsWeb Scraping › Brawl Tcg — Buscador Torneos Por Ciudad

Brawl Tcg — Buscador Torneos Por Ciudad

Brawl TCG — Buscador Torneos por Ciudad. Uses httpRequest. Scheduled trigger; 26 nodes.

Cron / scheduled trigger★★★★☆ complexity26 nodesHTTP Request
Web Scraping Trigger: Cron / scheduled Nodes: 26 Complexity: ★★★★☆ Added:

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": "Brawl TCG \u2014 Buscador Torneos por Ciudad",
  "nodes": [
    {
      "id": "schedule-trigger",
      "name": "Cada 6 Horas",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        200,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      }
    },
    {
      "id": "get-users",
      "name": "Obtener Usuarios",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        420,
        300
      ],
      "parameters": {
        "method": "GET",
        "url": "https://firestore.googleapis.com/v1/projects/brawl-tcg-database/databases/(default)/documents/User?pageSize=500",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "agrupar-ciudad",
      "name": "Agrupar por Ciudad",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        640,
        300
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst documents = response.documents || [];\nconst cityMap = {};\n\nfor (const doc of documents) {\n  const f = doc.fields || {};\n  const city = f.localidad?.stringValue;\n  const fcmToken = f.fcmToken?.stringValue;\n  const uid = doc.name.split('/').pop();\n  const email = f.email?.stringValue || '';\n\n  if (city && fcmToken) {\n    if (!cityMap[city]) cityMap[city] = [];\n    cityMap[city].push({ uid, fcmToken, email });\n  }\n}\n\nreturn Object.entries(cityMap).map(([city, users]) => ({\n  json: { city, users }\n}));"
      }
    },
    {
      "id": "loop-ciudades",
      "name": "Por Cada Ciudad",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        860,
        300
      ],
      "parameters": {
        "batchSize": 1,
        "options": {}
      }
    },
    {
      "id": "preparar-hashtags",
      "name": "Preparar Hashtags",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        160
      ],
      "parameters": {
        "jsCode": "const city = $json.city || '';\nconst cityTag = city.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').replace(/\\s+/g, '').toLowerCase();\nconst hashtags = [\n  `torneo${cityTag}`,\n  'torneotcg',\n  'torneomtg',\n  'torneoyugioh',\n  'torneopokemon',\n  'pokemontcg',\n  'magictcg',\n  'yugiohtorneo'\n];\nconst directUrls = hashtags.map(h => `https://www.instagram.com/explore/tags/${h}/`);\nreturn [{ json: { ...$json, cityTag, directUrls } }];"
      }
    },
    {
      "id": "buscar-instagram",
      "name": "Buscar en Instagram",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1320,
        160
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/apify~instagram-scraper/run-sync-get-dataset-items",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "timeout",
              "value": "120"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"directUrls\": {{ JSON.stringify($json.directUrls) }},\n  \"resultsType\": \"posts\",\n  \"resultsLimit\": 15\n}",
        "options": {
          "timeout": 120000
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "buscar-reddit",
      "name": "Buscar en Reddit",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1100,
        440
      ],
      "parameters": {
        "method": "GET",
        "url": "https://www.reddit.com/r/pkmntcg+magicTCG+yugioh+OnePieceTCG/search.json",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ 'torneo ' + $json.city + ' OR tournament ' + $json.city }}"
            },
            {
              "name": "sort",
              "value": "new"
            },
            {
              "name": "t",
              "value": "week"
            },
            {
              "name": "limit",
              "value": "15"
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "merge-redes",
      "name": "Unir Resultados",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        1340,
        300
      ],
      "parameters": {
        "mode": "append"
      }
    },
    {
      "id": "normalizar-posts",
      "name": "Normalizar Posts",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1560,
        300
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nconst normalized = [];\nconst city = $('Por Cada Ciudad').first().json.city || '';\n\nfor (const item of items) {\n  const data = item.json;\n\n  // Formato Instagram via Apify - items individuales\n  if (data.shortCode || data.inputUrl?.includes('instagram.com')) {\n    const url = data.url || (data.shortCode ? `https://www.instagram.com/p/${data.shortCode}/` : null);\n    if (!url) continue;\n    normalized.push({\n      json: {\n        platform: 'instagram',\n        sourceUrl: url,\n        text: data.caption || '',\n        imageUrl: data.displayUrl || data.imageUrl || null,\n        hashtags: (data.hashtags || []).map(h => '#' + h),\n        rawDate: data.timestamp || new Date().toISOString(),\n        city: data.locationName || city\n      }\n    });\n    continue;\n  }\n\n  // Formato Instagram via Apify - array (fallback)\n  if (Array.isArray(data)) {\n    for (const post of data) {\n      const url = post.url || (post.shortCode ? `https://www.instagram.com/p/${post.shortCode}/` : null);\n      if (!url) continue;\n      normalized.push({\n        json: {\n          platform: 'instagram',\n          sourceUrl: url,\n          text: post.caption || '',\n          imageUrl: post.displayUrl || post.imageUrl || null,\n          hashtags: (post.hashtags || []).map(h => '#' + h),\n          rawDate: post.timestamp || new Date().toISOString(),\n          city: post.locationName || city\n        }\n      });\n    }\n  }\n\n  // Formato Reddit\n  if (data.data?.children) {\n    for (const post of data.data.children) {\n      const p = post.data;\n      normalized.push({\n        json: {\n          platform: 'reddit',\n          sourceUrl: `https://reddit.com${p.permalink}`,\n          text: `${p.title} ${p.selftext || ''}`,\n          imageUrl: p.url_overridden_by_dest?.match(/\\.(jpg|png|gif|jpeg)/i)\n            ? p.url_overridden_by_dest : null,\n          hashtags: [],\n          rawDate: new Date(p.created_utc * 1000).toISOString(),\n          city: city\n        }\n      });\n    }\n  }\n}\n\nreturn normalized.length > 0 ? normalized : [{ json: { skip: true } }];"
      }
    },
    {
      "id": "tiene-imagen",
      "name": "Tiene Imagen",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1780,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "img-check",
              "leftValue": "={{ $json.imageUrl }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "imagen-a-base64",
      "name": "Imagen a Base64",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2080,
        160
      ],
      "parameters": {
        "jsCode": "const imageUrl = $json.imageUrl;\ntry {\n  const responseBuffer = await $helpers.httpRequest({\n    method: 'GET',\n    url: imageUrl,\n    headers: {\n      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n      'Referer': 'https://www.instagram.com/',\n      'Accept': 'image/webp,image/apng,image/*,*/*;q=0.8'\n    },\n    encoding: 'arraybuffer',\n    returnFullResponse: false\n  });\n  const base64 = Buffer.from(responseBuffer).toString('base64');\n  const visionBody = JSON.stringify({\n    requests: [{\n      image: { content: base64 },\n      features: [\n        { type: 'TEXT_DETECTION', maxResults: 1 },\n        { type: 'LABEL_DETECTION', maxResults: 10 }\n      ]\n    }]\n  });\n  return [{ json: { ...$json, visionBody } }];\n} catch (e) {\n  return [{ json: { ...$json, visionBody: null, downloadError: e.message } }];\n}"
      }
    },
    {
      "id": "vision-body-check",
      "name": "Vision Body Listo",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2260,
        160
      ],
      "parameters": {
        "conditions": {
          "options": {
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "vbody-check",
              "leftValue": "={{ $json.visionBody }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "google-vision",
      "name": "Analizar Imagen con Google Vision",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2260,
        160
      ],
      "parameters": {
        "method": "POST",
        "url": "https://vision.googleapis.com/v1/images:annotate",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.visionBody }}",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "procesar-vision",
      "name": "Procesar Respuesta Vision",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2260,
        160
      ],
      "parameters": {
        "jsCode": "const visionResponse = $input.first().json;\nconst originalPost = $('Tiene Imagen').first().json;\n\nconst response = visionResponse.responses?.[0] || {};\nconst fullText = (response.textAnnotations?.[0]?.description || '').toLowerCase();\nconst labels   = (response.labelAnnotations || []).map(l => l.description.toLowerCase());\n\nconst games = [\n  { key: 'Pokemon',  terms: ['pokemon', 'pok\u00e9mon', 'pkmn'] },\n  { key: 'Magic',    terms: ['magic', 'mtg', 'commander'] },\n  { key: 'YuGiOh',  terms: ['yugioh', 'yu-gi-oh', 'ygo'] },\n  { key: 'OnePiece',terms: ['one piece', 'optcg'] },\n  { key: 'Lorcana', terms: ['lorcana'] },\n  { key: 'FaB',     terms: ['flesh and blood', 'fab'] }\n];\n\nlet juego = null;\nfor (const g of games) {\n  if (g.terms.some(t => fullText.includes(t) || labels.some(l => l.includes(t)))) {\n    juego = g.key;\n    break;\n  }\n}\n\nconst esTorneo =\n  fullText.includes('torneo') ||\n  fullText.includes('tournament') ||\n  fullText.includes('campeonato') ||\n  labels.some(l => ['card game', 'games', 'tabletop game', 'collectible card game'].includes(l));\n\n// Extraer primera l\u00ednea como t\u00edtulo aproximado\nconst titulo = response.textAnnotations?.[0]?.description\n  ?.split('\\n')\n  .find(l => l.trim().length > 3) || null;\n\nreturn [{ json: { ...originalPost, analysis: { esTorneo, titulo, fecha: null, lugar: originalPost.city || null, juego } } }];"
      }
    },
    {
      "id": "inferir-texto",
      "name": "Inferir del Texto",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2020,
        440
      ],
      "parameters": {
        "jsCode": "const post = $input.first().json;\nconst text = (post.text || '').toLowerCase();\nconst hashtags = post.hashtags || [];\n\nconst games = [\n  { key: 'Pokemon',  terms: ['pokemon', 'pok\u00e9mon', 'pkmn'] },\n  { key: 'Magic',    terms: ['magic', 'mtg', 'commander'] },\n  { key: 'YuGiOh',  terms: ['yugioh', 'yu-gi-oh', 'ygo'] },\n  { key: 'OnePiece',terms: ['one piece', 'optcg'] },\n  { key: 'Lorcana', terms: ['lorcana'] },\n  { key: 'FaB',     terms: ['flesh and blood', 'fab'] }\n];\n\nlet juego = null;\nfor (const g of games) {\n  if (g.terms.some(t => text.includes(t) || hashtags.some(h => h.toLowerCase().includes(t)))) {\n    juego = g.key;\n    break;\n  }\n}\n\nconst esTorneo = text.includes('torneo') || text.includes('tournament') || text.includes('campeonato');\n\nreturn [{\n  json: {\n    ...post,\n    analysis: { esTorneo, titulo: null, fecha: null, lugar: post.city || null, juego }\n  }\n}];"
      }
    },
    {
      "id": "merge-analisis",
      "name": "Unir Analisis",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        2500,
        300
      ],
      "parameters": {
        "mode": "append"
      }
    },
    {
      "id": "es-torneo",
      "name": "Es Torneo",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2720,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "torneo-check",
              "leftValue": "={{ $json.analysis.esTorneo }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "check-duplicado",
      "name": "Buscar Duplicado",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2960,
        180
      ],
      "parameters": {
        "method": "POST",
        "url": "https://firestore.googleapis.com/v1/projects/brawl-tcg-database/databases/(default)/documents:runQuery",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"structuredQuery\": {\n    \"from\": [{ \"collectionId\": \"evento ia\" }],\n    \"where\": {\n      \"fieldFilter\": {\n        \"field\": { \"fieldPath\": \"sourceUrl\" },\n        \"op\": \"EQUAL\",\n        \"value\": { \"stringValue\": \"{{ $json.sourceUrl }}\" }\n      }\n    },\n    \"limit\": 1\n  }\n}",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "es-nuevo",
      "name": "Es Nuevo",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3180,
        180
      ],
      "parameters": {
        "jsCode": "const queryResult = $input.all();\nconst postData = $('Es Torneo').first().json;\n\nconst exists = queryResult.some(r => r.json.document);\n\nreturn [{ json: { ...postData, isDuplicate: exists } }];"
      }
    },
    {
      "id": "filtrar-dup",
      "name": "Filtrar Duplicados",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        3400,
        180
      ],
      "parameters": {
        "conditions": {
          "options": {
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "dup-check",
              "leftValue": "={{ $json.isDuplicate }}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "false"
              }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "guardar-evento-ia",
      "name": "Guardar en evento ia",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        3640,
        100
      ],
      "parameters": {
        "method": "POST",
        "url": "https://firestore.googleapis.com/v1/projects/brawl-tcg-database/databases/(default)/documents/evento%20ia",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"fields\": {\n    \"sourceUrl\":     { \"stringValue\": \"{{ $json.sourceUrl }}\" },\n    \"platform\":      { \"stringValue\": \"{{ $json.platform }}\" },\n    \"city\":          { \"stringValue\": \"{{ $('Por Cada Ciudad').first().json.city }}\" },\n    \"title\":         { \"stringValue\": \"{{ JSON.stringify($json.analysis.titulo || $json.text.substring(0,100)).slice(1,-1) }}\" },\n    \"description\":   { \"stringValue\": \"{{ JSON.stringify($json.text).slice(1,-1) }}\" },\n    \"imageUrl\":      { \"stringValue\": \"{{ $json.imageUrl || '' }}\" },\n    \"game\":          { \"stringValue\": \"{{ $json.analysis.juego || 'TCG' }}\" },\n    \"eventDate\":     { \"stringValue\": \"{{ $json.analysis.fecha || '' }}\" },\n    \"hashtags\":      { \"arrayValue\": { \"values\": [] } },\n    \"detectedAt\":    { \"timestampValue\": \"{{ new Date().toISOString() }}\" },\n    \"notifiedUsers\": { \"arrayValue\": { \"values\": [] } }\n  }\n}",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "get-users-ciudad",
      "name": "Usuarios de la Ciudad",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        3880,
        100
      ],
      "parameters": {
        "method": "POST",
        "url": "https://firestore.googleapis.com/v1/projects/brawl-tcg-database/databases/(default)/documents:runQuery",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"structuredQuery\": {\n    \"from\": [{ \"collectionId\": \"User\" }],\n    \"where\": {\n      \"compositeFilter\": {\n        \"op\": \"AND\",\n        \"filters\": [\n          {\n            \"fieldFilter\": {\n              \"field\": { \"fieldPath\": \"localidad\" },\n              \"op\": \"EQUAL\",\n              \"value\": { \"stringValue\": \"{{ $json.fields?.city?.stringValue }}\" }\n            }\n          },\n          {\n            \"fieldFilter\": {\n              \"field\": { \"fieldPath\": \"organizer\" },\n              \"op\": \"EQUAL\",\n              \"value\": { \"booleanValue\": false }\n            }\n          }\n        ]\n      }\n    }\n  }\n}",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "preparar-usuarios",
      "name": "Preparar Usuarios",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4120,
        100
      ],
      "parameters": {
        "jsCode": "const queryResults = $input.all();\nconst eventSaved = $('Guardar en evento ia').first().json;\n\nconst eventFields = eventSaved.fields || {};\nconst eventTitle = eventFields.title?.stringValue || 'Nuevo torneo TCG';\nconst eventCity  = eventFields.city?.stringValue  || '';\nconst eventGame  = eventFields.game?.stringValue  || 'TCG';\nconst sourceUrl  = eventFields.sourceUrl?.stringValue || '';\nconst platform   = eventFields.platform?.stringValue  || '';\n\nconst users = [];\n\nfor (const item of queryResults) {\n  // Firestore runQuery devuelve un array; n8n puede envolverlo en un solo item\n  const docs = Array.isArray(item.json) ? item.json : [item.json];\n  for (const result of docs) {\n    const doc = result.document || result;\n    if (!doc || !doc.fields) continue;\n    const f   = doc.fields;\n    const uid = (doc.name || '').split('/').pop();\n    const fcm = f.fcmToken?.stringValue;\n    if (fcm) users.push({ uid, fcmToken: fcm, email: f.email?.stringValue || '' });\n  }\n}\n\nreturn users.map(u => ({\n  json: { ...u, eventTitle, eventCity, eventGame, sourceUrl, platform }\n}));"
      }
    },
    {
      "id": "loop-usuarios",
      "name": "Por Cada Usuario",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        4360,
        100
      ],
      "parameters": {
        "batchSize": 1,
        "options": {}
      }
    },
    {
      "id": "crear-notif-inapp",
      "name": "Crear Notificacion In-App",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        4600,
        -40
      ],
      "parameters": {
        "method": "POST",
        "url": "https://firestore.googleapis.com/v1/projects/brawl-tcg-database/databases/(default)/documents/Notifications",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"fields\": {\n    \"date\":    { \"timestampValue\": \"{{ new Date().toISOString() }}\" },\n    \"mensaje\": { \"stringValue\": \"Torneo {{ $json.eventGame }} encontrado en {{ $json.eventCity }}: {{ JSON.stringify($json.eventTitle).slice(1,-1) }}\" },\n    \"type\":    { \"stringValue\": \"discovered_event\" },\n    \"userID\":  { \"referenceValue\": \"projects/brawl-tcg-database/databases/(default)/documents/User/{{ $json.uid }}\" },\n    \"link\":    { \"stringValue\": \"{{ $json.sourceUrl }}\" }\n  }\n}",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "enviar-push-fcm",
      "name": "Enviar Push FCM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        4600,
        240
      ],
      "parameters": {
        "method": "POST",
        "url": "https://fcm.googleapis.com/v1/projects/brawl-tcg-database/messages:send",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message\": {\n    \"token\": \"{{ $json.fcmToken }}\",\n    \"notification\": {\n      \"title\": \"Torneo {{ $json.eventGame }} en {{ $json.eventCity }}\",\n      \"body\":  \"{{ JSON.stringify($json.eventTitle).slice(1,-1) }}\"\n    },\n    \"data\": {\n      \"type\":     \"discovered_event\",\n      \"link\":     \"{{ $json.sourceUrl }}\",\n      \"platform\": \"{{ $json.platform }}\",\n      \"city\":     \"{{ $json.eventCity }}\"\n    },\n    \"android\": {\n      \"notification\": {\n        \"click_action\": \"FLUTTER_NOTIFICATION_CLICK\"\n      }\n    }\n  }\n}",
        "options": {}
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Cada 6 Horas": {
      "main": [
        [
          {
            "node": "Obtener Usuarios",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obtener Usuarios": {
      "main": [
        [
          {
            "node": "Agrupar por Ciudad",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Agrupar por Ciudad": {
      "main": [
        [
          {
            "node": "Por Cada Ciudad",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Por Cada Ciudad": {
      "main": [
        [
          {
            "node": "Preparar Hashtags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Hashtags": {
      "main": [
        [
          {
            "node": "Buscar en Instagram",
            "type": "main",
            "index": 0
          },
          {
            "node": "Buscar en Reddit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar en Instagram": {
      "main": [
        [
          {
            "node": "Unir Resultados",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar en Reddit": {
      "main": [
        [
          {
            "node": "Unir Resultados",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Unir Resultados": {
      "main": [
        [
          {
            "node": "Normalizar Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalizar Posts": {
      "main": [
        [
          {
            "node": "Tiene Imagen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tiene Imagen": {
      "main": [
        [
          {
            "node": "Imagen a Base64",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Inferir del Texto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Imagen a Base64": {
      "main": [
        [
          {
            "node": "Vision Body Listo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vision Body Listo": {
      "main": [
        [
          {
            "node": "Analizar Imagen con Google Vision",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Inferir del Texto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analizar Imagen con Google Vision": {
      "main": [
        [
          {
            "node": "Procesar Respuesta Vision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Procesar Respuesta Vision": {
      "main": [
        [
          {
            "node": "Unir Analisis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inferir del Texto": {
      "main": [
        [
          {
            "node": "Unir Analisis",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Unir Analisis": {
      "main": [
        [
          {
            "node": "Es Torneo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Es Torneo": {
      "main": [
        [
          {
            "node": "Buscar Duplicado",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Buscar Duplicado": {
      "main": [
        [
          {
            "node": "Es Nuevo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Es Nuevo": {
      "main": [
        [
          {
            "node": "Filtrar Duplicados",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filtrar Duplicados": {
      "main": [
        [
          {
            "node": "Guardar en evento ia",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Guardar en evento ia": {
      "main": [
        [
          {
            "node": "Usuarios de la Ciudad",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Usuarios de la Ciudad": {
      "main": [
        [
          {
            "node": "Preparar Usuarios",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Usuarios": {
      "main": [
        [
          {
            "node": "Por Cada Usuario",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Por Cada Usuario": {
      "main": [
        [
          {
            "node": "Crear Notificacion In-App",
            "type": "main",
            "index": 0
          },
          {
            "node": "Enviar Push FCM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

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

About this workflow

Brawl TCG — Buscador Torneos por Ciudad. Uses httpRequest. Scheduled trigger; 26 nodes.

Source: https://github.com/LiorACP/Brawl_TCG/blob/a8a823e73d6b36e5b251f7035de9a38ebf3702b1/n8n/brawl_tcg_torneos.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

Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.

Stop And Error, HTTP Request, Email Send +1
Web Scraping

This template runs two scheduled workflows to govern Microsoft Entra ID (Azure AD) guest accounts by detecting stale users via Microsoft Graph, staging deletions in SharePoint with a 72-hour window, n

Microsoft SharePoint, Microsoft Teams, Microsoft Entra +1
Web Scraping

Jira-Allure-Auto-Qa. Uses httpRequest, jira. Scheduled trigger; 68 nodes.

HTTP Request, Jira
Web Scraping

Spotify-Sync-Surrealdb-V1. Uses httpRequest, n8n-nodes-surrealdb, spotify. Scheduled trigger; 62 nodes.

HTTP Request, N8N Nodes Surrealdb, Spotify
Web Scraping

As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o

HTTP Request, n8n, N8N Trigger +1