{
  "id": "O0oQNpVv6RYoK3w6OUFHN",
  "name": "Auto-unpublish ImageKit assets that fail NSFW check",
  "tags": [],
  "nodes": [
    {
      "id": "81ecd665-4e9a-4a33-9c31-5f3cc069fb68",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -80
      ],
      "parameters": {
        "width": 480,
        "height": 660,
        "content": "## \ud83d\udd1e Auto-unpublish ImageKit Assets That Fail NSFW Check\n\n**Who is this for?**\nTeams that allow user-generated or third-party image uploads to ImageKit and need an automated safety layer to prevent inappropriate content from going live.\n\n**What it does**\nWhen a new file is uploaded to ImageKit, this workflow automatically downloads it, runs it through an AI vision model for NSFW detection, and unpublishes it if flagged \u2014 before it can be served via CDN.\n\n**How it works**\n1. ImageKit fires a webhook on `file.created`\n2. The image is downloaded as binary via HTTP\n3. GPT-4o Vision analyzes the image and returns a structured JSON verdict\n4. If `is_nsfw` is `true`, the file is immediately unpublished in ImageKit\n5. Clean images pass through without any action\n\n**Setup checklist**\n- [ ] Add **ImageKit** webhook credentials in *New File Upload* node\n- [ ] Add **ImageKit** API credentials in *Unpublish File* node\n- [ ] Add **OpenRouter** credentials with access to `openai/gpt-4o` in *GPT-4o Vision* node\n- [ ] In ImageKit dashboard, ensure new uploads default to **published** so this workflow acts as the gatekeeper"
      },
      "typeVersion": 1
    },
    {
      "id": "89b5b817-2709-44a9-87a4-357ad921fd55",
      "name": "Section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        -80
      ],
      "parameters": {
        "color": 4,
        "width": 408,
        "height": 348,
        "content": "### 1\ufe0f\u20e3 Trigger & Download\nImageKit fires a `file.created` event on every new upload. The image is immediately downloaded as binary so it can be passed to the vision model."
      },
      "typeVersion": 1
    },
    {
      "id": "b1dfcd8f-e0fd-4c5d-9ce9-cf8a02ae831f",
      "name": "Section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        -80
      ],
      "parameters": {
        "color": 6,
        "width": 380,
        "height": 524,
        "content": "### 2\ufe0f\u20e3 AI Vision Analysis\nGPT-4o receives the binary image via **Automatically Passthrough Binary Images** and returns a structured JSON verdict with `is_nsfw`, `confidence`, and `reason`."
      },
      "typeVersion": 1
    },
    {
      "id": "7997b488-a5f0-4414-b2ae-6150167bf133",
      "name": "Section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1312,
        -80
      ],
      "parameters": {
        "color": 3,
        "width": 360,
        "height": 364,
        "content": "### 3\ufe0f\u20e3 Decision & Action\nIf `is_nsfw` is `true`, the file is unpublished in ImageKit immediately. If clean, the workflow exits without any action."
      },
      "typeVersion": 1
    },
    {
      "id": "a56bbaac-d36c-4e75-aad8-c90ff28bcd84",
      "name": "Confidence Threshold Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1312,
        304
      ],
      "parameters": {
        "width": 356,
        "height": 140,
        "content": "\u2139\ufe0f **Confidence threshold**\nCurrently flags any image where `is_nsfw` is `true` regardless of confidence score. To reduce false positives, add a second condition in the IF node:\n`confidence >= 0.85`"
      },
      "typeVersion": 1
    },
    {
      "id": "28089e15-9332-4d8d-8513-950e84487fee",
      "name": "New File Upload",
      "type": "@imagekit/n8n-nodes-imagekit.imagekitTrigger",
      "position": [
        544,
        80
      ],
      "parameters": {
        "events": [
          "file.created"
        ]
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "b4ecf825-db34-4c21-a653-d81cf2887a42",
      "name": "Download Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        768,
        80
      ],
      "parameters": {
        "url": "={{ $json.data.url }}",
        "options": {}
      },
      "typeVersion": 4.3
    },
    {
      "id": "d2649fab-a3c9-48fe-b57e-c5bce11041bc",
      "name": "GPT-4o Vision",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        992,
        80
      ],
      "parameters": {
        "text": "=You are a content moderation system. Analyze this image and respond with JSON only:\n\n{\n  \"is_nsfw\": true | false,\n  \"confidence\": 0.0 - 1.0,\n  \"reason\": \"one sentence explanation or null\"\n}\n\nFlag as nsfw if the image contains nudity, sexual content, graphic violence, or gore.\nDo not flag artistic nudity in classical paintings or medical imagery.\n",
        "options": {
          "passthroughBinaryImages": true
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "6117625b-2c23-45ef-909f-0af8fbfb50bf",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1008,
        304
      ],
      "parameters": {
        "model": "openai/gpt-4o",
        "options": {}
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "0cd0169f-3f93-445e-8a28-7ed01dc362f3",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1136,
        304
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"is_nsfw\": true,\n  \"confidence\": 0.0,\n  \"reason\": \"one sentence explanation or null\"\n}\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "20e8dc2e-9c0b-4d54-9524-4d9dc7477844",
      "name": "Is NSFW?",
      "type": "n8n-nodes-base.if",
      "position": [
        1344,
        80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6cae5400-52a1-4390-bd8f-433875dc19ed",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.output.is_nsfw }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d70fd671-9534-4c06-abae-e2f2cada09d6",
      "name": "Unpublish File",
      "type": "@imagekit/n8n-nodes-imagekit.imagekit",
      "position": [
        1536,
        16
      ],
      "parameters": {
        "fileId": "={{ $('New File Upload').item.json.data.fileId }}",
        "resource": "file",
        "operation": "publish",
        "isPublished": false
      },
      "credentials": {},
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "589b9eee-7512-45d4-9c3a-edb6cf5a82b0",
  "connections": {
    "Is NSFW?": {
      "main": [
        [
          {
            "node": "Unpublish File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GPT-4o Vision": {
      "main": [
        [
          {
            "node": "Is NSFW?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Image": {
      "main": [
        [
          {
            "node": "GPT-4o Vision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New File Upload": {
      "main": [
        [
          {
            "node": "Download Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "GPT-4o Vision",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "GPT-4o Vision",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  }
}