AutomationFlowsWeb Scraping › Openthai.ai Content Generator

Openthai.ai Content Generator

Openthai.ai Content Generator. Uses httpRequest. Webhook trigger; 11 nodes.

Webhook trigger★★★★☆ complexity11 nodesHTTP Request
Web Scraping Trigger: Webhook Nodes: 11 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": "Openthai.ai Content Generator",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "openthai-ai",
        "options": {}
      },
      "id": "webhook-trigger",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// S7: Context Compression \u2014 \u0e2a\u0e23\u0e49\u0e32\u0e07 Context Card 5 fields\nconst input = $input.first().json;\n\nconst contextCard = {\n  product_name: input.product_name || '',\n  category: input.category || 'otop',\n  key_features: input.features || [],\n  target_audience: input.audience || '\u0e04\u0e19\u0e44\u0e17\u0e22\u0e17\u0e31\u0e48\u0e27\u0e44\u0e1b',\n  unique_selling_point: input.usp || '',\n  hook_preference: input.hook_type || 'auto'\n};\n\n// Compress to ~150 chars for efficient context\nconst compressed = `${contextCard.product_name}|${contextCard.category}|${contextCard.target_audience}|${contextCard.hook_preference}`;\n\nreturn {\n  contextCard,\n  compressed,\n  timestamp: new Date().toISOString()\n};"
      },
      "id": "context-card",
      "name": "S7: Context Card",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        200
      ]
    },
    {
      "parameters": {
        "url": "https://sheets.googleapis.com/v4/spreadsheets/YOUR_SHEET_ID/values/Products!A:Z",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "options": {}
      },
      "id": "knowledge-base",
      "name": "S8: Knowledge Base",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        450,
        400
      ],
      "notes": "\u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19 YOUR_SHEET_ID \u0e40\u0e1b\u0e47\u0e19 Google Sheet ID \u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13"
    },
    {
      "parameters": {
        "jsCode": "// S1+S3+S5: Prompt Assembly\n// \u0e23\u0e27\u0e21 RCCF Prompt + Master Prompt + Category System Prompt\n\nconst context = $('S7: Context Card').first().json;\nconst knowledge = $('S8: Knowledge Base').first().json;\n\n// S5: Category-specific system prompts\nconst systemPrompts = {\n  food: '\u0e04\u0e38\u0e13\u0e40\u0e1b\u0e47\u0e19\u0e1c\u0e39\u0e49\u0e40\u0e0a\u0e35\u0e48\u0e22\u0e27\u0e0a\u0e32\u0e0d\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c TikTok \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e2d\u0e32\u0e2b\u0e32\u0e23\u0e44\u0e17\u0e22 \u0e40\u0e19\u0e49\u0e19: \u0e23\u0e2a\u0e0a\u0e32\u0e15\u0e34, \u0e2a\u0e39\u0e15\u0e23\u0e42\u0e1a\u0e23\u0e32\u0e13, \u0e27\u0e31\u0e15\u0e16\u0e38\u0e14\u0e34\u0e1a\u0e17\u0e49\u0e2d\u0e07\u0e16\u0e34\u0e48\u0e19',\n  craft: '\u0e04\u0e38\u0e13\u0e40\u0e1b\u0e47\u0e19\u0e1c\u0e39\u0e49\u0e40\u0e0a\u0e35\u0e48\u0e22\u0e27\u0e0a\u0e32\u0e0d\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c TikTok \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e2b\u0e31\u0e15\u0e16\u0e01\u0e23\u0e23\u0e21 \u0e40\u0e19\u0e49\u0e19: \u0e1d\u0e35\u0e21\u0e37\u0e2d\u0e0a\u0e48\u0e32\u0e07, \u0e20\u0e39\u0e21\u0e34\u0e1b\u0e31\u0e0d\u0e0d\u0e32, \u0e01\u0e23\u0e30\u0e1a\u0e27\u0e19\u0e01\u0e32\u0e23\u0e1c\u0e25\u0e34\u0e15',\n  herb: '\u0e04\u0e38\u0e13\u0e40\u0e1b\u0e47\u0e19\u0e1c\u0e39\u0e49\u0e40\u0e0a\u0e35\u0e48\u0e22\u0e27\u0e0a\u0e32\u0e0d\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c TikTok \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e2a\u0e21\u0e38\u0e19\u0e44\u0e1e\u0e23 \u0e40\u0e19\u0e49\u0e19: \u0e2a\u0e23\u0e23\u0e1e\u0e04\u0e38\u0e13, \u0e27\u0e34\u0e18\u0e35\u0e43\u0e0a\u0e49, \u0e1c\u0e25\u0e25\u0e31\u0e1e\u0e18\u0e4c',\n  textile: '\u0e04\u0e38\u0e13\u0e40\u0e1b\u0e47\u0e19\u0e1c\u0e39\u0e49\u0e40\u0e0a\u0e35\u0e48\u0e22\u0e27\u0e0a\u0e32\u0e0d\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c TikTok \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e1c\u0e49\u0e32\u0e17\u0e2d \u0e40\u0e19\u0e49\u0e19: \u0e25\u0e27\u0e14\u0e25\u0e32\u0e22, \u0e01\u0e23\u0e30\u0e1a\u0e27\u0e19\u0e01\u0e32\u0e23\u0e22\u0e49\u0e2d\u0e21, heritage',\n  global: '\u0e04\u0e38\u0e13\u0e40\u0e1b\u0e47\u0e19\u0e1c\u0e39\u0e49\u0e40\u0e0a\u0e35\u0e48\u0e22\u0e27\u0e0a\u0e32\u0e0d\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c TikTok \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32\u0e17\u0e31\u0e48\u0e27\u0e44\u0e1b \u0e40\u0e19\u0e49\u0e19: \u0e04\u0e27\u0e32\u0e21\u0e04\u0e38\u0e49\u0e21\u0e04\u0e48\u0e32, \u0e1f\u0e35\u0e40\u0e08\u0e2d\u0e23\u0e4c\u0e40\u0e14\u0e48\u0e19, \u0e40\u0e17\u0e23\u0e19\u0e14\u0e4c'\n};\n\nconst category = context.contextCard?.category || 'global';\nconst systemPrompt = systemPrompts[category] || systemPrompts.global;\n\n// S3: Master Prompt\nconst masterPrompt = `\n\u3010OUTPUT FORMAT\u3011\n\u0e2a\u0e23\u0e49\u0e32\u0e07\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c TikTok 30 \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35:\n1. Hook (3 \u0e27\u0e34): \u0e14\u0e36\u0e07\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e19\u0e43\u0e08\u0e17\u0e31\u0e19\u0e17\u0e35\n2. Story (20 \u0e27\u0e34): \u0e40\u0e19\u0e37\u0e49\u0e2d\u0e2b\u0e32\u0e2b\u0e25\u0e31\u0e01\n3. CTA (7 \u0e27\u0e34): Call to Action\n\n\u0e1e\u0e23\u0e49\u0e2d\u0e21 Caption + 10 Hashtags\n\n\u0e15\u0e2d\u0e1a\u0e40\u0e1b\u0e47\u0e19 JSON \u0e40\u0e17\u0e48\u0e32\u0e19\u0e31\u0e49\u0e19:\n{\n  \"script\": {\"hook\": \"...\", \"story\": \"...\", \"cta\": \"...\"},\n  \"caption\": \"...\",\n  \"hashtags\": [\"...\"],\n  \"hook_type\": \"...\",\n  \"why_it_works\": \"...\"\n}\n`;\n\n// S1: RCCF Prompt (Role, Context, Constraint, Format)\nconst userPrompt = `\n\u3010\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32\u3011${context.contextCard?.product_name}\n\u3010\u0e2b\u0e21\u0e27\u0e14\u0e2b\u0e21\u0e39\u0e48\u3011${category}\n\u3010\u0e01\u0e25\u0e38\u0e48\u0e21\u0e40\u0e1b\u0e49\u0e32\u0e2b\u0e21\u0e32\u0e22\u3011${context.contextCard?.target_audience}\n\u3010Hook \u0e17\u0e35\u0e48\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u3011${context.contextCard?.hook_preference}\n\n${masterPrompt}\n`;\n\nreturn {\n  systemPrompt,\n  userPrompt,\n  context: context.contextCard,\n  iteration: 1\n};"
      },
      "id": "prompt-assembly",
      "name": "S1+S3+S5: Prompt Assembly",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        300
      ]
    },
    {
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"claude-sonnet-4-5-20251001\",\n  \"max_tokens\": 2000,\n  \"system\": \"{{ $json.systemPrompt }}\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"{{ $json.userPrompt }}\"\n    }\n  ]\n}",
        "options": {}
      },
      "id": "claude-generate",
      "name": "Claude Generate",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        950,
        300
      ],
      "notes": "\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32 HTTP Header Auth: x-api-key = YOUR_ANTHROPIC_API_KEY"
    },
    {
      "parameters": {
        "jsCode": "// S6: AI Critic \u2014 \u0e43\u0e2b\u0e49\u0e04\u0e30\u0e41\u0e19\u0e19\u0e41\u0e25\u0e30 feedback\nconst response = $input.first().json;\nconst content = JSON.parse(response.content[0].text);\n\n// \u0e04\u0e33\u0e19\u0e27\u0e13\u0e04\u0e30\u0e41\u0e19\u0e19\u0e15\u0e32\u0e21\u0e40\u0e01\u0e13\u0e11\u0e4c\nfunction calculateScore(content) {\n  let score = 0;\n  \n  // Hook strength (30%)\n  const hookLength = content.script?.hook?.length || 0;\n  if (hookLength > 20 && hookLength < 100) score += 3;\n  \n  // Story flow (25%)\n  const storyLength = content.script?.story?.length || 0;\n  if (storyLength > 100 && storyLength < 500) score += 2.5;\n  \n  // CTA clarity (20%)\n  const ctaLength = content.script?.cta?.length || 0;\n  if (ctaLength > 20 && ctaLength < 100) score += 2;\n  \n  // Hashtags (15%)\n  const hashtagCount = content.hashtags?.length || 0;\n  if (hashtagCount >= 8) score += 1.5;\n  \n  // Format compliance (10%)\n  if (content.hook_type && content.why_it_works) score += 1;\n  \n  return Math.min(10, score);\n}\n\nconst criticScore = calculateScore(content);\n\nreturn {\n  content,\n  criticScore,\n  passed: criticScore >= 7,\n  feedback: criticScore >= 7 \n    ? '\u0e04\u0e2d\u0e19\u0e40\u0e17\u0e19\u0e15\u0e4c\u0e1c\u0e48\u0e32\u0e19\u0e21\u0e32\u0e15\u0e23\u0e10\u0e32\u0e19' \n    : '\u0e15\u0e49\u0e2d\u0e07\u0e1b\u0e23\u0e31\u0e1a\u0e1b\u0e23\u0e38\u0e07: ' + (criticScore < 5 ? 'Hook \u0e2d\u0e48\u0e2d\u0e19' : '\u0e40\u0e1e\u0e34\u0e48\u0e21 detail'),\n  iteration: $('S1+S3+S5: Prompt Assembly').first().json.iteration\n};"
      },
      "id": "ai-critic",
      "name": "S6: AI Critic",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.passed }}",
              "value2": true
            }
          ],
          "number": [
            {
              "value1": "={{ $json.iteration }}",
              "operation": "smaller",
              "value2": 4
            }
          ]
        },
        "combineOperation": "any"
      },
      "id": "if-gate",
      "name": "IF: Score \u2265 7 or Max 3x",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1400,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// S2: Taste Check \u2014 \u0e15\u0e23\u0e27\u0e08\u0e2a\u0e2d\u0e1a\u0e01\u0e31\u0e1a reference library\nconst input = $input.first().json;\nconst content = input.content;\n\n// \u0e15\u0e31\u0e27\u0e2d\u0e22\u0e48\u0e32\u0e07 taste check (\u0e43\u0e19\u0e08\u0e23\u0e34\u0e07\u0e08\u0e30\u0e40\u0e17\u0e35\u0e22\u0e1a\u0e01\u0e31\u0e1a reference lib)\nconst tasteChecks = {\n  hasEmoji: /[\\u{1F300}-\\u{1F9FF}]/u.test(content.caption || ''),\n  hashtagCount: (content.hashtags?.length || 0) >= 8,\n  hookNotGeneric: !['\u0e23\u0e39\u0e49\u0e44\u0e2b\u0e21', '\u0e40\u0e04\u0e22\u0e40\u0e2b\u0e47\u0e19'].some(w => content.script?.hook?.includes(w)),\n  ctaHasAction: ['\u0e01\u0e14', 'follow', '\u0e25\u0e2d\u0e07', '\u0e0b\u0e37\u0e49\u0e2d', '\u0e2a\u0e31\u0e48\u0e07'].some(w => \n    (content.script?.cta || '').toLowerCase().includes(w)\n  )\n};\n\nconst tasteScore = Object.values(tasteChecks).filter(Boolean).length * 2.5;\n\nreturn {\n  ...input,\n  tasteScore,\n  tasteChecks\n};"
      },
      "id": "taste-check",
      "name": "S2: Taste Check",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1600,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "// S9: Learning Layer \u2014 \u0e2d\u0e18\u0e34\u0e1a\u0e32\u0e22 why it works\nconst input = $input.first().json;\n\nconst learning = {\n  hook_type: input.content.hook_type || 'auto',\n  why_it_works: input.content.why_it_works || 'Hook \u0e19\u0e35\u0e49\u0e43\u0e0a\u0e49\u0e44\u0e14\u0e49\u0e40\u0e1e\u0e23\u0e32\u0e30\u0e14\u0e36\u0e07\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e19\u0e43\u0e08\u0e17\u0e31\u0e19\u0e17\u0e35',\n  next_try: `\u0e25\u0e2d\u0e07\u0e43\u0e0a\u0e49 Hook \u0e41\u0e1a\u0e1a ${['story', 'process', 'contrast', 'question', 'transformation'].filter(h => h !== input.content.hook_type)[0]} \u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32\u0e19\u0e35\u0e49`\n};\n\nreturn {\n  content: input.content,\n  quality: {\n    critic_score: input.criticScore,\n    taste_score: input.tasteScore,\n    iterations: input.iteration\n  },\n  learning\n};"
      },
      "id": "learning-layer",
      "name": "S9: Learning Layer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1800,
        200
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "id": "response",
      "name": "Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        2000,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "// Retry loop \u2014 \u0e40\u0e1e\u0e34\u0e48\u0e21 iteration \u0e41\u0e25\u0e30 retry\nconst input = $input.first().json;\n\nreturn {\n  ...input,\n  iteration: input.iteration + 1,\n  retry: true\n};"
      },
      "id": "retry-loop",
      "name": "Retry Loop",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1600,
        400
      ]
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "S7: Context Card",
            "type": "main",
            "index": 0
          },
          {
            "node": "S8: Knowledge Base",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "S7: Context Card": {
      "main": [
        [
          {
            "node": "S1+S3+S5: Prompt Assembly",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "S8: Knowledge Base": {
      "main": [
        [
          {
            "node": "S1+S3+S5: Prompt Assembly",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "S1+S3+S5: Prompt Assembly": {
      "main": [
        [
          {
            "node": "Claude Generate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Generate": {
      "main": [
        [
          {
            "node": "S6: AI Critic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "S6: AI Critic": {
      "main": [
        [
          {
            "node": "IF: Score \u2265 7 or Max 3x",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Score \u2265 7 or Max 3x": {
      "main": [
        [
          {
            "node": "S2: Taste Check",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Retry Loop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "S2: Taste Check": {
      "main": [
        [
          {
            "node": "S9: Learning Layer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "S9: Learning Layer": {
      "main": [
        [
          {
            "node": "Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retry Loop": {
      "main": [
        [
          {
            "node": "S1+S3+S5: Prompt Assembly",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    "openthai-ai",
    "tiktok",
    "content-generation"
  ],
  "triggerCount": 0,
  "updatedAt": "2026-04-01T00:00:00.000Z",
  "versionId": "1.0.0"
}
Pro

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

About this workflow

Openthai.ai Content Generator. Uses httpRequest. Webhook trigger; 11 nodes.

Source: https://github.com/occylthailand-ai/openthai-ai/blob/a54555497095210210ff6ecc34ce8c68a523f147/n8n-workflows/openthai-ai-workflow.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

This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di

n8n, Execute Workflow Trigger, HTTP Request +1
Web Scraping

This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .

HTTP Request, Ssh
Web Scraping

eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.

HTTP Request
Web Scraping

This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia

HTTP Request
Web Scraping

This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c

HTTP Request