{
  "id": "JeFVMY0AmBGhogu1",
  "name": "Backfill studio product photos for single-image Shopify products with Dreem.ai",
  "tags": [],
  "nodes": [
    {
      "id": "bac338f2-fca8-483d-b686-012dc1095cc7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Backfill studio product photos for single-image Shopify products with Dreem.ai\n\n### How it works\n\nThis workflow manually backfills studio-style product photos for Shopify products that currently have only a single image. It fetches products, filters for missing shots, loops through each item, generates front and back renders with Dreem.ai, asks for Slack approval on the front shot, and publishes approved/completed images back to Shopify. Slack is also used to notify when items are skipped and when the full run is complete.\n\n### Setup steps\n\n- Configure Shopify credentials and confirm the product query returns the catalog segment you want to backfill.\n- Configure Dreem.ai credentials and set the front/back render prompts or product-image inputs in the Dreem nodes.\n- Configure Slack credentials, the review channel, approval interaction settings, and completion/skipped notification destinations.\n- Review the filter logic in \u201cMissing Product Shots?\u201d so it matches your definition of single-image or missing-photo products.\n- Adjust wait durations and completion checks to match typical Dreem.ai render times and response fields.\n\n### Customization\n\nYou can change the product filter, batch size, Slack approval wording, Dreem.ai render prompts, and whether back shots require a separate approval step before publishing."
      },
      "typeVersion": 1
    },
    {
      "id": "68178e17-d00b-434b-a72d-25b8e4ae2b35",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        224
      ],
      "parameters": {
        "color": 7,
        "width": 912,
        "height": 352,
        "content": "## Select products to process\n\nStarts the manual backfill, retrieves Shopify products, filters for items missing additional product shots, and batches them one product at a time for downstream processing."
      },
      "typeVersion": 1
    },
    {
      "id": "b1744bc4-315d-42fe-ace0-e1a1e8090a0e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 368,
        "content": "## Generate front shots\n\nRequests a front-facing studio render from Dreem.ai for the current product and pauses to allow the render job to complete."
      },
      "typeVersion": 1
    },
    {
      "id": "358f8430-2e49-48ed-a9e4-e792807e9339",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2160,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 688,
        "content": "## Review rendered shots\n\nChecks whether the front render completed, posts completed shots to Slack for review, captures approval, and sends skipped notifications when rendering is incomplete or later rejected paths need to move on."
      },
      "typeVersion": 1
    },
    {
      "id": "12b73dd0-36ee-4e27-98f4-f941f6647a3b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        96
      ],
      "parameters": {
        "color": 7,
        "height": 368,
        "content": "## Publish approved front\n\nUploads the approved front product shot back to Shopify before starting the secondary back-shot generation path."
      },
      "typeVersion": 1
    },
    {
      "id": "29301fdd-994c-4a32-8e88-12e0120a63e5",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        800
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 336,
        "content": "## Generate back shots\n\nRuns the back-view Dreem.ai render, waits for completion, verifies the result, and publishes completed back shots to Shopify before returning to the product loop."
      },
      "typeVersion": 1
    },
    {
      "id": "70007855-1e77-4eb8-9e54-be340b3fad0e",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        -128
      ],
      "parameters": {
        "color": 7,
        "height": 368,
        "content": "## Send completion notice\n\nPosts a Slack notification when the product batch loop has no more matching products to process."
      },
      "typeVersion": 1
    },
    {
      "id": "995011f5-13e0-4c5e-b7d3-fe473beea3ba",
      "name": "Start Workflow Manually",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        608,
        400
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "76a2d1a2-b10b-4dd7-8388-e7f058f491eb",
      "name": "Fetch Shopify Products",
      "type": "n8n-nodes-base.shopify",
      "position": [
        848,
        400
      ],
      "parameters": {
        "resource": "product",
        "operation": "getAll",
        "returnAll": true,
        "authentication": "accessToken",
        "additionalFields": {}
      },
      "credentials": {
        "shopifyAccessTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dab6ea68-0cc0-49d6-b615-f96707e8d21e",
      "name": "Filter Missing Photos",
      "type": "n8n-nodes-base.filter",
      "position": [
        1088,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7ef567b8-e6d4-47f6-836f-0a20ce0f4c8a",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.tags }}",
              "rightValue": "dreem-shots-added"
            },
            {
              "id": "c4a90d12-58be-4f21-9a3e-7d2f6b1e8a01",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ ($json.images ?? []).length }}",
              "rightValue": 1
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "287efcdc-c8ec-4bc4-bee5-c4cea2eedc03",
      "name": "Post Completion on Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1568,
        80
      ],
      "parameters": {
        "text": "=Dreem product shots run complete. Every product missing shots has been processed.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.5
    },
    {
      "id": "3ac8d016-566e-42a7-a451-947415043476",
      "name": "Create Front View Images",
      "type": "n8n-nodes-dreem.dreem",
      "position": [
        1568,
        528
      ],
      "parameters": {
        "operation": "generateProductShots",
        "shotCodes": [
          "flat_lay_front",
          "invisible_mannequin_front"
        ],
        "callbackUrl": "={{ $execution.resumeUrl }}",
        "backImageUrl": "={{ $json.images?.[1]?.src ?? '' }}",
        "outputFormat": "jpeg",
        "frontImageUrl": "={{ $json.images[0].src }}",
        "authentication": "apiKey",
        "outputAspectRatio": 5
      },
      "typeVersion": 1
    },
    {
      "id": "943f4567-26d6-42b1-ab0f-56f2a0ff9f3f",
      "name": "Wait for Image Render",
      "type": "n8n-nodes-base.wait",
      "position": [
        1792,
        528
      ],
      "parameters": {
        "resume": "webhook",
        "options": {},
        "httpMethod": "POST",
        "resumeUnit": "minutes",
        "resumeAmount": 20,
        "limitWaitTime": true
      },
      "typeVersion": 1.1
    },
    {
      "id": "95cac5a4-fa11-4a30-b553-6ca437da89a3",
      "name": "Check Render Completion",
      "type": "n8n-nodes-base.if",
      "position": [
        2240,
        528
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.body?.status ?? $json.status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "72f0eedf-41cd-416b-bf40-a715bf0f4af3",
      "name": "Request Approval on Slack",
      "type": "n8n-nodes-base.slack",
      "disabled": true,
      "position": [
        2448,
        448
      ],
      "parameters": {
        "select": "channel",
        "message": "=Approve the product shots above for *{{ $('Loop Through Product Batches').item.json.title }}*? *Approve & publish* adds them to the product; *Skip* leaves it untouched (and untagged, so it's retried next run).",
        "options": {
          "limitWaitTime": {
            "values": {
              "resumeAmount": 24
            }
          }
        },
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "operation": "sendAndWait",
        "authentication": "oAuth2",
        "approvalOptions": {
          "values": {
            "approvalType": "double",
            "approveLabel": "Approve & publish",
            "disapproveLabel": "Skip"
          }
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "ed937219-7705-4719-ab4f-43050a3390c6",
      "name": "Check Approval Status",
      "type": "n8n-nodes-base.if",
      "disabled": true,
      "position": [
        2672,
        448
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.approved }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "80dbd52c-8475-43a8-b32e-21ad9d3d73c9",
      "name": "Loop Through Product Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1328,
        400
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "8ba71729-4dfc-4381-b630-6b6b2a89bf78",
      "name": "Notify Skipped Photos",
      "type": "n8n-nodes-base.slack",
      "position": [
        2448,
        640
      ],
      "parameters": {
        "text": "=Skipped *{{ $('Loop Through Product Batches').item.json.title }}* - the render did not finish in time. If its shots weren't added yet, it will be picked up again on the next run.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.5
    },
    {
      "id": "535b2597-4a58-4fe3-8ccf-27b1a7995e2b",
      "name": "Update Front Photos",
      "type": "n8n-nodes-base.shopify",
      "position": [
        3056,
        352
      ],
      "parameters": {
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('Loop Through Product Batches').item.json.id }}",
        "updateFields": {
          "tags": "={{ [$('Loop Through Product Batches').item.json.tags, 'dreem-shots-added'].filter(Boolean).join(', ') }}",
          "images": "={{ ($('Loop Through Product Batches').item.json.images || []).map(i => ({ id: i.id })).concat(($('Wait for Image Render').item.json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        },
        "authentication": "accessToken"
      },
      "typeVersion": 1
    },
    {
      "id": "78c1bcdd-b5d2-4e9c-a689-28bce720f0eb",
      "name": "Create Back View Images",
      "type": "n8n-nodes-dreem.dreem",
      "disabled": true,
      "position": [
        1568,
        960
      ],
      "parameters": {
        "operation": "generateProductShots",
        "shotCodes": [
          "flat_lay_back",
          "invisible_mannequin_back"
        ],
        "callbackUrl": "={{ $execution.resumeUrl }}",
        "backImageUrl": "={{ $('Loop Through Product Batches').item.json.images?.[1]?.src ?? '' }}",
        "outputFormat": "jpeg",
        "frontImageUrl": "={{ $('Loop Through Product Batches').item.json.images[0].src }}",
        "authentication": "apiKey",
        "outputAspectRatio": 5
      },
      "typeVersion": 1
    },
    {
      "id": "4109e2d1-d518-41e5-83f4-604803dbe71a",
      "name": "Wait for Back Image Render",
      "type": "n8n-nodes-base.wait",
      "disabled": true,
      "position": [
        1792,
        960
      ],
      "parameters": {
        "resume": "webhook",
        "options": {},
        "httpMethod": "POST",
        "resumeUnit": "minutes",
        "resumeAmount": 20,
        "limitWaitTime": true
      },
      "typeVersion": 1.1
    },
    {
      "id": "03331b66-f7b5-445f-8fe7-b7f8410c8300",
      "name": "Check Back Render Completion",
      "type": "n8n-nodes-base.if",
      "disabled": true,
      "position": [
        2016,
        960
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.body?.status ?? $json.status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e26f0301-b4f2-4e1d-87f7-62f848592e16",
      "name": "Update Back Photos",
      "type": "n8n-nodes-base.shopify",
      "disabled": true,
      "position": [
        2240,
        960
      ],
      "parameters": {
        "resource": "product",
        "operation": "update",
        "productId": "={{ $('Loop Through Product Batches').item.json.id }}",
        "updateFields": {
          "images": "={{ ($('Update Front Photos').item.json.images || []).map(i => ({ id: i.id })).concat(($('Wait for Back Image Render').item.json.body.outputs || []).map(o => ({ src: o.files[0].url }))) }}"
        },
        "authentication": "accessToken"
      },
      "typeVersion": 1
    },
    {
      "id": "3fb7c2e0-96a2-4462-946b-df222b3c6517",
      "name": "Send Images to Slack for Review",
      "type": "n8n-nodes-base.slack",
      "disabled": true,
      "position": [
        2208,
        272
      ],
      "parameters": {
        "text": "=*Product shots ready for review* \u2014 {{ $('Loop Through Product Batches').item.json.title }}\n{{ ($('Wait for Image Render').item.json.body?.outputs ?? $('Wait for Image Render').item.json.outputs ?? []).map(o => o.files[0].url).join('\\n') }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.5
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "dd44d49b-90a7-41df-aafe-b0450b362389",
  "nodeGroups": [],
  "connections": {
    "Update Back Photos": {
      "main": [
        [
          {
            "node": "Loop Through Product Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Front Photos": {
      "main": [
        [
          {
            "node": "Create Back View Images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Approval Status": {
      "main": [
        [
          {
            "node": "Update Front Photos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Through Product Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Missing Photos": {
      "main": [
        [
          {
            "node": "Loop Through Product Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Skipped Photos": {
      "main": [
        [
          {
            "node": "Loop Through Product Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Image Render": {
      "main": [
        [
          {
            "node": "Check Render Completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Shopify Products": {
      "main": [
        [
          {
            "node": "Filter Missing Photos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Render Completion": {
      "main": [
        [
          {
            "node": "Send Images to Slack for Review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify Skipped Photos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Back View Images": {
      "main": [
        [
          {
            "node": "Wait for Back Image Render",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Workflow Manually": {
      "main": [
        [
          {
            "node": "Fetch Shopify Products",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Front View Images": {
      "main": [
        [
          {
            "node": "Wait for Image Render",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Request Approval on Slack": {
      "main": [
        [
          {
            "node": "Check Approval Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Back Image Render": {
      "main": [
        [
          {
            "node": "Check Back Render Completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Back Render Completion": {
      "main": [
        [
          {
            "node": "Update Back Photos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify Skipped Photos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Through Product Batches": {
      "main": [
        [
          {
            "node": "Post Completion on Slack",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Front View Images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Images to Slack for Review": {
      "main": [
        [
          {
            "node": "Request Approval on Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}