diff --git a/workflows/Find and add lookalike influencers to HubSpot with influencers.club and GPT-4o-mini-13514/find_and_add_lookalike_influencers_to_hubspot_with_influencers.club_and_gpt-4o-mini.json b/workflows/Find and add lookalike influencers to HubSpot with influencers.club and GPT-4o-mini-13514/find_and_add_lookalike_influencers_to_hubspot_with_influencers.club_and_gpt-4o-mini.json new file mode 100644 index 000000000..859e37d75 --- /dev/null +++ b/workflows/Find and add lookalike influencers to HubSpot with influencers.club and GPT-4o-mini-13514/find_and_add_lookalike_influencers_to_hubspot_with_influencers.club_and_gpt-4o-mini.json @@ -0,0 +1 @@ +{"id":"XJMLz8j7z4G2GMWI","meta":{"instanceId":"85adf2a35c28eb4259098779e620f01802fefc169e5e72d95fa3a1fcdca8b513","templateCredsSetupCompleted":true},"name":"Find and add similar creators to Hubspot based on top performers","tags":[],"nodes":[{"id":"d1c4d36e-79fb-4876-8d57-84a514b96fd3","name":"📋 OVERVIEW","type":"n8n-nodes-base.stickyNote","position":[-160,1232],"parameters":{"color":4,"width":600,"height":568,"content":"# HubSpot → Lookalike Creator Discovery\n\n**How it works** When a contact is created in HubSpot, this pipeline checks if they're a creator, finds similar creators via the influencers.club API, enriches and AI-analyzes each one, then pushes qualified lookalikes back into HubSpot.\n\n**Flow:** Trigger → Fetch contact → Extract email → Enrich → Detect platform → Filter creators → Lookalike API → Loop each result → Enrich → Normalize → AI analysis → HubSpot upsert\n\n**Platform detection:** `main_platform` is auto-detected by comparing follower counts across TikTok / Instagram / YouTube / Twitter — the highest audience wins. Non-creators are silently dropped at the Filter node.\n\n**Set up required**\n- HubSpot Developer App (trigger)\n- HubSpot App Token (read + write)\n- influencers.club API key\n- OpenAI API key"},"typeVersion":1},{"id":"0647f8b5-0314-46bd-9731-c1576e276ef8","name":"Note: Trigger","type":"n8n-nodes-base.stickyNote","position":[480,1360],"parameters":{"color":3,"width":200,"height":442,"content":"## HubSpot Trigger\nFires on `contact.creation`. Outputs `contactId` for the next node.\n\nAdd `contact.propertyChange` in HubSpot app settings to also catch updates."},"typeVersion":1},{"id":"101be7b1-471f-433d-8089-91f1362cfb36","name":"Note: Get Contact","type":"n8n-nodes-base.stickyNote","position":[768,1360],"parameters":{"color":3,"width":216,"height":442,"content":"## Get Contact by ID\nFetches `firstname`, `company`, `hs_full_name_or_email` from HubSpot using `contactId`.\n\n Add more properties to `propertiesCollection` if your CRM has custom creator fields."},"typeVersion":1},{"id":"8c416418-b1c9-4bcd-85f3-39bd1cb644c2","name":"Note: Extract Email","type":"n8n-nodes-base.stickyNote","position":[1040,1360],"parameters":{"color":3,"width":200,"height":442,"content":"## Extract Email\nMaps HubSpot fields into clean `Email` and `Company Name` variables.\n"},"typeVersion":1},{"id":"0f815d99-c44b-4855-8606-2a038f44e072","name":"Note: Enrich by Email","type":"n8n-nodes-base.stickyNote","position":[1296,1248],"parameters":{"color":6,"width":216,"height":414,"content":"## Enrich by Email\nPOSTs email to influencers.club and returns a full main profile info.\n\n Error → Stop and Error node."},"typeVersion":1},{"id":"b3279d61-a380-4e30-8646-ee3087e83a95","name":"Note: Stop and Error","type":"n8n-nodes-base.stickyNote","position":[1296,1680],"parameters":{"color":7,"width":206,"height":348,"content":"## Stop and Error\nTriggered when enrichment fails or returns no creator. Halts execution with a logged error message."},"typeVersion":1},{"id":"2535f18d-8add-4ae5-a961-da92f7b40170","name":"Note: Normalize Seed","type":"n8n-nodes-base.stickyNote","position":[1552,1104],"parameters":{"color":7,"width":210,"height":552,"content":"## Normalize (Code in JS)\nDetects `main_platform` by comparing follower counts across all platform blocks. Computes `follower_tier`, `engagement_tier`, `growth_trend`. Strips CloudFront URL signing params.\n\nOutputs a flat clean object for the filter and lookalike nodes."},"typeVersion":1},{"id":"4c97fb61-7f2b-4cad-a41a-d9f97a805131","name":"Note: Filter","type":"n8n-nodes-base.stickyNote","position":[1792,1104],"parameters":{"color":7,"width":190,"height":544,"content":"## Filter — Is Creator?\nChecks `is_creator === true`. Only real creators proceed.\n\n**Port 0** → Lookalike API \n**Port 1** → dead end, dropped silently "},"typeVersion":1},{"id":"143bc619-8c10-4b3d-b7e7-8840054a748b","name":"Note: Lookalike API","type":"n8n-nodes-base.stickyNote","position":[2016,1104],"parameters":{"color":6,"width":392,"height":542,"content":"## Lookalike API\nFinds similar creators using `main_platform` + `handle`. Returns up to 5 accounts.\n\n Adjust `paging.limit` (max ~50) or add filters: `engagement_percent.min`, `number_of_followers`, `has_done_brand_deals: true`."},"typeVersion":1},{"id":"463f103b-c8b7-49c2-bdaf-077315d2308d","name":"Note: Loop","type":"n8n-nodes-base.stickyNote","position":[2448,1104],"parameters":{"color":7,"width":190,"height":544,"content":"## Loop Over Items\nProcesses one lookalike at a time to avoid API rate limits.\n\n**Port 0** → all done, exits loop\n**Port 1** → next item → Enrichment API"},"typeVersion":1},{"id":"efa995d5-d67a-4247-9b8a-74fea9430c43","name":"Note: AI Agent","type":"n8n-nodes-base.stickyNote","position":[3184,1120],"parameters":{"color":2,"width":370,"height":690,"content":"## AI Agent\nGPT-4o-mini analyzes the profile and returns structured JSON: summary, strengths, concerns, audience authenticity, growth trajectory, niche clarity, brand fit, recommended action, and estimated reach per post.\n\n Edit the system prompt to add campaign context or scoring bias."},"typeVersion":1},{"id":"1568debf-2a3d-465f-af1b-c0c191cd38b5","name":"Note: HubSpot Out","type":"n8n-nodes-base.stickyNote","position":[3616,1120],"parameters":{"color":3,"width":210,"height":692,"content":"## HubSpot Upsert\nCreates or updates the lookalike as a HubSpot contact using their enriched email.\n\n Map `recommended_action`, `brand_fit`, and `estimated_reach_per_post` to custom HubSpot properties for outreach sequencing."},"typeVersion":1},{"id":"e9a4aab9-fe47-4ca5-8bbd-6f9bcefb7bab","name":"Stop and Error","type":"n8n-nodes-base.stopAndError","position":[1344,1840],"parameters":{"errorMessage":"API enrichment failed - contact is not a creator or API error"},"typeVersion":1},{"id":"111cf880-1d0a-4327-bffd-13c3f98d9420","name":"OpenAI Model (Lookalike)1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[3200,1712],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{},"builtInTools":{}},"credentials":{"openAiApi":{"id":"W8cxWjHLmpqoLcGC","name":"N8N open AI"}},"typeVersion":1.3},{"id":"e2f24be3-9aef-4970-b98e-b6edf1f77562","name":"Structured Output Parser (Lookalike)1","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[3456,1712],"parameters":{"schemaType":"manual","inputSchema":"{\n \"type\": \"object\",\n \"properties\": {\n \"summary\": { \"type\": \"string\" },\n \"strengths\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } },\n \"concerns\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } },\n \"audience_analysis\": { \"type\": \"object\", \"properties\": { \"authenticity_assessment\": { \"type\": \"string\" }, \"engagement_quality\": { \"type\": \"string\", \"enum\": [\"low\",\"medium\",\"high\"] }, \"engagement_notes\": { \"type\": \"string\" } }, \"required\": [\"authenticity_assessment\",\"engagement_quality\",\"engagement_notes\"] },\n \"growth_analysis\": { \"type\": \"object\", \"properties\": { \"trajectory\": { \"type\": \"string\", \"enum\": [\"declining\",\"stagnant\",\"steady\",\"accelerating\"] }, \"notes\": { \"type\": \"string\" } }, \"required\": [\"trajectory\",\"notes\"] },\n \"content_analysis\": { \"type\": \"object\", \"properties\": { \"content_style\": { \"type\": \"string\" }, \"niche_clarity\": { \"type\": \"string\", \"enum\": [\"weak\",\"moderate\",\"strong\"] }, \"niche_notes\": { \"type\": \"string\" } }, \"required\": [\"content_style\",\"niche_clarity\",\"niche_notes\"] },\n \"brand_fit\": { \"type\": \"object\", \"properties\": { \"best_fit_categories\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }, \"poor_fit_categories\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }, \"campaign_types\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } } }, \"required\": [\"best_fit_categories\",\"poor_fit_categories\",\"campaign_types\"] },\n \"flags\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } },\n \"recommended_action\": { \"type\": \"string\", \"enum\": [\"approve\",\"review\",\"reject\"] },\n \"recommended_action_reason\": { \"type\": \"string\" },\n \"estimated_reach_per_post\": { \"type\": \"object\", \"properties\": { \"low\": { \"type\": \"number\" }, \"high\": { \"type\": \"number\" }, \"basis\": { \"type\": \"string\" } }, \"required\": [\"low\",\"high\",\"basis\"] }\n },\n \"required\": [\"summary\",\"strengths\",\"concerns\",\"audience_analysis\",\"growth_analysis\",\"content_analysis\",\"brand_fit\",\"flags\",\"recommended_action\",\"recommended_action_reason\",\"estimated_reach_per_post\"]\n}"},"typeVersion":1.3},{"id":"7194259e-6ac6-42ba-a445-70cc7de5f6f2","name":"Note: Enrich Lookalike1","type":"n8n-nodes-base.stickyNote","position":[2704,1104],"parameters":{"color":6,"width":424,"height":538,"content":"## Enrich Lookalike\nFetches full profile per lookalike: post data, audience, income, connected platforms.\n\n Error output suppressed — failed enrichments skip silently so the loop continues."},"typeVersion":1},{"id":"63f881e0-5adc-4b9b-8b1d-1d77c9a1c5b8","name":"HubSpot Trigger","type":"n8n-nodes-base.hubspotTrigger","position":[528,1648],"webhookId":"883eeb6e-1df3-425b-adcd-cfaf795d1937","parameters":{"eventsUi":{"eventValues":[{}]},"additionalFields":{"maxConcurrentRequests":5}},"credentials":{"hubspotDeveloperApi":{"id":"yDRt3bHZGhZMcFva","name":"Dzole Hubspot Developer"}},"typeVersion":1},{"id":"016d7e62-a2d7-4ba9-9f9e-998eec74648a","name":"Get Contact by ID","type":"n8n-nodes-base.hubspot","position":[832,1648],"parameters":{"contactId":{"__rl":true,"mode":"id","value":"={{ $json.contactId }}"},"operation":"get","authentication":"appToken","additionalFields":{"propertiesCollection":{"propertiesValues":{"properties":["firstname","company","hs_full_name_or_email"]}}}},"credentials":{"hubspotAppToken":{"id":"69g6my3KrUsJEGYR","name":"gorgi hubspot"}},"typeVersion":2.2},{"id":"e35885d7-64d4-412b-89b3-21d460bd39e9","name":"Extract Email","type":"n8n-nodes-base.set","position":[1088,1648],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8ff17193-2e32-487b-b433-14cc67ee0581","name":"Email","type":"string","value":"={{ $json.properties.email.value }}"},{"id":"first-name-extract","name":"Company Name","type":"string","value":"={{ $json[\"associated-company\"].properties.name.value }}"}]}},"typeVersion":3.4},{"id":"2235d40b-0612-4a15-a6f4-38d5022ad0ed","name":"Normalize","type":"n8n-nodes-base.code","position":[1616,1472],"parameters":{"jsCode":"const raw = $input.first().json[0] || $input.first().json;\nconst result = raw.result || raw;\n\nfunction fmtFollowers(n) {\n if (n == null) return null;\n if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`;\n if (n >= 1000) return `${Math.round(n / 1000)}K`;\n return `${n}`;\n}\n\nfunction stripUrl(url) {\n if (!url || typeof url !== 'string') return null;\n return url.includes('?') ? url.split('?')[0] : url;\n}\n\nfunction engagementTier(pct) {\n if (pct == null) return 'unknown';\n if (pct >= 5) return 'high';\n if (pct >= 1) return 'medium';\n return 'low';\n}\n\nfunction followerTier(n) {\n if (n == null) return 'unknown';\n if (n >= 500000) return 'macro';\n if (n >= 100000) return 'mid';\n if (n >= 10000) return 'micro';\n return 'nano';\n}\n\nfunction growthTrend(g) {\n if (!g || typeof g !== 'object') return null;\n const vals = [g['12_months_ago'], g['9_months_ago'], g['6_months_ago'], g['3_months_ago']]\n .filter(v => typeof v === 'number');\n if (vals.length < 2) return null;\n return vals[vals.length - 1] > vals[0] ? 'accelerating' : 'decelerating';\n}\n\nconst platforms = {\n tiktok: { data: result.tiktok || null, followers: result.tiktok?.follower_count ?? 0 },\n instagram: { data: result.instagram || null, followers: result.instagram?.follower_count ?? 0 },\n youtube: { data: result.youtube || null, followers: result.youtube?.subscriber_count ?? 0 },\n twitter: { data: result.twitter || null, followers: result.twitter?.follower_count ?? 0 }\n};\n\nconst main_platform = Object.entries(platforms)\n .filter(([, v]) => v.data && v.followers > 0)\n .sort((a, b) => b[1].followers - a[1].followers)[0]?.[0] || 'unknown';\n\nconst p = platforms[main_platform]?.data || {};\nconst followers = platforms[main_platform]?.followers || null;\nconst handle = (p.username || '').replace(/^@/, '').toLowerCase().trim() || null;\n\nconst profileUrls = {\n tiktok: handle ? `https://www.tiktok.com/@${handle}` : null,\n instagram: handle ? `https://www.instagram.com/${handle}` : null,\n youtube: p.custom_url ? `https://www.youtube.com/${p.custom_url}` : null,\n twitter: handle ? `https://twitter.com/${handle}` : null\n};\n\nreturn [{\n json: {\n email: result.email || null,\n email_type: result.email_type || null,\n full_name: p.full_name || result.first_name?.replace(/^@/, '') || null,\n handle,\n display_handle: handle ? `@${handle}` : null,\n main_platform,\n profile_url: profileUrls[main_platform] || null,\n profile_picture: stripUrl(p.profile_picture),\n followers,\n followers_fmt: fmtFollowers(followers),\n follower_tier: followerTier(followers),\n engagement_percent: p.engagement_percent ? parseFloat(p.engagement_percent.toFixed(3)) : null,\n engagement_tier: engagementTier(p.engagement_percent),\n growth_trend: growthTrend(p.creator_follower_growth),\n posting_frequency: p.posting_frequency_recent_months ?? null,\n biography: p.biography || null,\n is_verified: p.is_verified || false,\n is_creator: result.is_creator || false,\n has_brand_deals: result.has_brand_deals || false,\n has_merch: p.has_merch || false,\n promotes_affiliate_links: p.promotes_affiliate_links || false,\n gender: result.gender || null,\n location: result.location || null,\n speaking_language: result.speaking_language || null,\n links_in_bio: result.links_in_bio || p.links_in_bio || [],\n platforms_available: Object.entries(platforms)\n .filter(([, v]) => v.data && v.followers > 0)\n .map(([name, v]) => ({ platform: name, followers: v.followers, followers_fmt: fmtFollowers(v.followers) }))\n }\n}];"},"typeVersion":2},{"id":"4564d50a-7773-4049-a032-8d1324b47bc7","name":"Filter - Is Creator?","type":"n8n-nodes-base.if","position":[1840,1472],"parameters":{"options":{},"conditions":{"options":{"version":1,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"creator-check","operator":{"type":"boolean","operation":"equals"},"leftValue":"={{ $json.is_creator }}","rightValue":true}]}},"typeVersion":2},{"id":"72e1331d-6e7a-4167-a158-4289af48e1bf","name":"Loop Over Items (Lookalike)","type":"n8n-nodes-base.splitInBatches","position":[2512,1456],"parameters":{"options":{}},"typeVersion":3},{"id":"9b7ba1b6-8a14-40db-a12c-15200566cf2b","name":"Normalize Profile (Lookalike)","type":"n8n-nodes-base.code","position":[2992,1456],"parameters":{"mode":"runOnceForEachItem","jsCode":"function stripUrl(url){if(!url)return null;return typeof url==='string'&&url.includes('?')?url.split('?')[0]:url;}\nfunction normHandle(raw){if(!raw||typeof raw!=='string')return null;return raw.replace(/^@/,'').toLowerCase().trim();}\nfunction fmtFollowers(n){if(n==null)return null;if(n>=1000000)return`${(n/1000000).toFixed(1)}M`;if(n>=1000)return`${(n/1000).toFixed(0)}K`;return`${n}`;}\nfunction growthTrend(g){if(!g||typeof g!=='object')return null;const vals=[g['12_months_ago'],g['9_months_ago'],g['6_months_ago'],g['3_months_ago']].filter(v=>typeof v==='number');if(vals.length<2)return null;return vals[vals.length-1]>vals[0]?'accelerating':'decelerating';}\nfunction buildLinks(ch,handle){const l={};if(!handle)return l;if(Array.isArray(ch)){ch.forEach(e=>{if(e&&typeof e==='object')Object.entries(e).forEach(([p,u])=>{if(u)l[p]=u;});});}else if(ch&&typeof ch==='object'){if(ch.has_instagram||ch.instagram)l.instagram=`https://www.instagram.com/${handle}`;if(ch.has_tiktok)l.tiktok=`https://www.tiktok.com/@${handle}`;if(ch.has_youtube)l.youtube=`https://www.youtube.com/@${handle}`;if(ch.has_twitter)l.twitter=`https://twitter.com/${handle}`;if(ch.has_linktree)l.linktree=`https://linktr.ee/${handle}`;}return l;}\nfunction dedupCollabs(tagged){if(!Array.isArray(tagged))return[];const c={};tagged.forEach(t=>{if(t?.username)c[t.username]=(c[t.username]||0)+1;});return Object.entries(c).sort((a,b)=>b[1]-a[1]).slice(0,8).map(([u])=>u);}\n\nfunction normalize(entry) {\n // Detect format A: { result: { instagram: {...}, ... }, credits_cost: 1 }\n // Detect format B: { user_id, profile: { username, followers, ... } }\n // Detect format C: flat enriched data directly\n\n const isFormatA = !!(entry.result && entry.result.instagram);\n const isFormatB = !!(entry.profile && entry.profile.username);\n\n if (isFormatB) {\n // Lightweight lookalike format\n const profile = entry.profile;\n const handle = normHandle(profile.username);\n const followers = profile.followers ?? null;\n const engPct = profile.engagement_percent ?? null;\n return {\n normalized_profile: {\n identity: {\n user_id: entry.user_id || null,\n full_name: profile.full_name || null,\n handle,\n display_handle: handle ? `@${handle}` : null,\n platform_primary: 'instagram',\n profile_url: handle ? `https://www.instagram.com/${handle}` : null,\n profile_picture: stripUrl(profile.picture),\n email: null, is_verified: false, is_private: false,\n is_business_account: false, account_type: 'personal',\n category: null, niche_topics: []\n },\n cross_platform_links: { instagram: handle ? `https://www.instagram.com/${handle}` : null },\n contact: { email: null, email_type: null, phone: null, has_link_in_bio: false, bio_links: [] },\n audience: { follower_count: followers, follower_count_fmt: fmtFollowers(followers), following_count: null, media_count: null, top_country: null, state: null, city: null, location_certainty: null, language: null },\n follower_growth: null,\n engagement: { engagement_percent: engPct, avg_likes: null, avg_comments: null, median_likes: null, median_comments: null, comment_to_like_ratio_pct: null },\n content: { posting_frequency_per_month: null, reels_percentage: null, video_content_creator: false, most_recent_post_date: null, top_hashtags: [], biography: null },\n monetization: { has_brand_deals: false, has_merch: false, promotes_affiliate_links: false, estimated_income: null },\n network: { frequent_collaborators: [], primary_locations: [] },\n flags: { low_engagement: typeof engPct==='number'&&typeof followers==='number'&&engPct<1.0&&followers>10000, tiktok_id_only: false },\n dedup_key: handle ? `instagram:${handle}` : entry.user_id ? `instagram:${entry.user_id}` : null\n }\n };\n }\n\n // Format A or C — full enrichment data\n const raw = isFormatA ? entry.result : entry;\n const ig = raw.instagram || {};\n\n const handle = normHandle(ig?.username || ig?.handle || raw?.creator_handle);\n const userId = ig?.userid || ig?.user_id || raw?.user_id || null;\n const email = raw?.email || raw?.contact_email || ig?.email || null;\n const followers = ig?.follower_count ?? ig?.followers ?? null;\n const engPct = ig?.engagement_percent ?? null;\n const avgLikes = ig?.avg_likes ?? ig?.average_likes ?? null;\n const avgComments = ig?.avg_comments ?? ig?.average_comments ?? null;\n const ctlRatio = (typeof avgLikes==='number'&&avgLikes>0&&typeof avgComments==='number') ? parseFloat(((avgComments/avgLikes)*100).toFixed(2)) : null;\n const ch = raw?.creator_has || ig?.creator_has || null;\n const xp = buildLinks(ch, handle);\n if(handle && !xp.instagram) xp.instagram = `https://www.instagram.com/${handle}`;\n const lt = ig?.linktree || raw?.linktree || null;\n if(lt && !xp.linktree) xp.linktree = `https://linktr.ee/${lt}`;\n const gr = ig?.creator_follower_growth || null;\n const fg = gr ? {'3_months_ago_pct':gr['3_months_ago']??null,'6_months_ago_pct':gr['6_months_ago']??null,'9_months_ago_pct':gr['9_months_ago']??null,'12_months_ago_pct':gr['12_months_ago']??null,trend:growthTrend(gr)} : null;\n const aud = { follower_count: followers, follower_count_fmt: fmtFollowers(followers), following_count: ig?.following_count??null, media_count: ig?.media_count??null, top_country: ig?.country||raw?.location||null, state: ig?.state||null, city: ig?.city||null, location_certainty: ig?.location_certainty??null, language: Array.isArray(ig?.language_code)?ig.language_code[0]:(raw?.speaking_language||ig?.language_code||null) };\n const collabs = dedupCollabs(ig?.tagged||[]).filter(u=>u!==handle);\n const locs = [...new Set((ig?.locations||[]).filter(Boolean))].slice(0,5);\n const incRaw = ig?.income || raw?.income_data?.instagram || null;\n const inc = incRaw ? {min_usd:incRaw.min??null,max_usd:incRaw.max??null,currency:incRaw.currency??null} : null;\n let tags = [];\n if(Array.isArray(ig?.hashtags_count)&&ig.hashtags_count.length){ tags=ig.hashtags_count.sort((a,b)=>b.count-a.count).slice(0,10).map(h=>h.name); }\n else if(Array.isArray(ig?.hashtags)){ const seen=new Set(); tags=ig.hashtags.filter(h=>h&&h.length>1&&!seen.has(h)&&seen.add(h)).slice(0,10); }\n const dk = handle?`instagram:${handle}`:userId?`instagram:${userId}`:null;\n\n return {\n normalized_profile: {\n identity: { user_id: userId, full_name: ig?.full_name||raw?.first_name||null, handle, display_handle: handle?`@${handle}`:null, platform_primary:'instagram', profile_url: handle?`https://www.instagram.com/${handle}`:null, profile_picture: stripUrl(ig?.profile_picture||ig?.profile_picture_hd), email, is_verified: ig?.is_verified??false, is_private: ig?.is_private??false, is_business_account: ig?.is_business_account??raw?.is_business??false, account_type: raw?.is_creator?'creator':(ig?.account_type===3?'creator':'personal'), category: ig?.category||null, niche_topics: ig?.niche_class||[] },\n cross_platform_links: xp,\n contact: { email, email_type: raw?.email_type||null, phone: raw?.contact_phone_number?`+${String(raw.contact_phone_number).replace(/^\\+/,'')}` :(ig?.contact_phone_number||null), has_link_in_bio: ig?.uses_link_in_bio??raw?.has_link_in_bio??false, bio_links: ig?.links_in_bio||raw?.links_in_bio||[] },\n audience: aud,\n follower_growth: fg,\n engagement: { engagement_percent: engPct, avg_likes: avgLikes, avg_comments: avgComments, median_likes: ig?.likes_median??null, median_comments: ig?.comments_median??null, comment_to_like_ratio_pct: ctlRatio },\n content: { posting_frequency_per_month: ig?.posting_frequency_recent_months??null, reels_percentage: ig?.reels_percentage_last_12_posts??null, video_content_creator: ig?.video_content_creator??false, most_recent_post_date: ig?.most_recent_post_date||null, top_hashtags: tags, biography: ig?.biography||null },\n monetization: { has_brand_deals: raw?.has_brand_deals??ig?.has_done_brand_deals??false, has_merch: ig?.has_merch??false, promotes_affiliate_links: ig?.promotes_affiliate_links??false, estimated_income: inc },\n network: { frequent_collaborators: collabs, primary_locations: locs },\n flags: { low_engagement: typeof engPct==='number'&&typeof followers==='number'&&engPct<1.0&&followers>10000, tiktok_id_only: !!(xp.tiktok&&/\\/\\d{10,}/.test(xp.tiktok)) },\n dedup_key: dk\n }\n };\n}\n\n// Handle array or single item\nconst input = item.json;\nif (Array.isArray(input)) {\n return input.map(entry => ({ json: normalize(entry) }));\n} else {\n return { json: normalize(input) };\n}"},"typeVersion":2},{"id":"946fa69c-5f24-4c02-9fa4-e14fc23756ca","name":"AI Agent (Lookalike)","type":"@n8n/n8n-nodes-langchain.agent","position":[3264,1456],"parameters":{"text":"=Analyze the following normalized creator profile and provide a structured analysis.\n\nCreator Profile:\n{{ JSON.stringify($json.normalized_profile, null, 2) }}\n\nRespond ONLY with this JSON structure, no markdown, no extra text:\n\n{\n \"summary\": \"2-3 sentence overview of who this creator is and their positioning\",\n \"strengths\": [\"Specific strength with data evidence\"],\n \"concerns\": [\"Specific concern with data evidence\"],\n \"audience_analysis\": { \"authenticity_assessment\": \"string\", \"engagement_quality\": \"low | medium | high\", \"engagement_notes\": \"string\" },\n \"growth_analysis\": { \"trajectory\": \"declining | stagnant | steady | accelerating\", \"notes\": \"string\" },\n \"content_analysis\": { \"content_style\": \"string\", \"niche_clarity\": \"weak | moderate | strong\", \"niche_notes\": \"string\" },\n \"brand_fit\": { \"best_fit_categories\": [\"string\"], \"poor_fit_categories\": [\"string\"], \"campaign_types\": [\"string\"] },\n \"flags\": [\"string\"],\n \"recommended_action\": \"approve | review | reject\",\n \"recommended_action_reason\": \"string\",\n \"estimated_reach_per_post\": { \"low\": 0, \"high\": 0, \"basis\": \"string\" }\n}","options":{"systemMessage":"You are an expert influencer marketing analyst with deep knowledge of Instagram metrics, creator monetization, audience authenticity signals, and brand partnership strategy. Always respond with valid JSON only — no markdown code blocks, no preamble, no explanation outside the JSON object."},"promptType":"define","hasOutputParser":true},"typeVersion":3.1},{"id":"8e8da4f7-704a-4432-bf46-d13436963325","name":"HubSpot — Lookalike Creator","type":"n8n-nodes-base.hubspot","position":[3680,1456],"parameters":{"email":"=","options":{},"authentication":"appToken","additionalFields":{}},"credentials":{"hubspotAppToken":{"id":"69g6my3KrUsJEGYR","name":"gorgi hubspot"}},"typeVersion":2.2},{"id":"330f7dcb-4cf1-4f5f-b87f-d6ff47a29809","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[1552,688],"parameters":{"width":752,"content":"## Find similar creators to your top performers and boost your brand visibility\n**Step by step workflow to discover lookalike creators with multi social (Instagram, Tiktok, Youtube, Twitter, Onlyfans, Twitch and more) data using the influencer.club API and add them to Hubspot**. [https://influencers.club/creatorbook/find-similar-creators-to-top-performers/)"},"typeVersion":1},{"id":"ec6d791c-a379-41ac-af84-fc71ea2affc0","name":"Enrich by Email","type":"n8n-nodes-influencersclub.influencersClub","onError":"continueErrorOutput","position":[1360,1488],"parameters":{"email":"={{ $json.Email }}"},"credentials":{"influencersClubApi":{"id":"pfuQoV9XcYUVIeuU","name":"Influencers Club - Gjorgji"}},"typeVersion":1},{"id":"4bac64d4-7688-46b7-b87f-77d630c074a8","name":"Find Similar Creators","type":"n8n-nodes-influencersclub.influencersClub","position":[2080,1456],"parameters":{"platform":"={{ $json.main_platform }}","resource":"creator","operation":"findLookalikes","filter_key":"username","filter_value":"={{ $json.handle }}","tiktokFilters":{},"twitchFilters":{},"twitterFilters":{},"youtubeFilters":{},"advancedFilters":{},"onlyfansFilters":{},"instagramFilters":{},"additionalOptions":{}},"credentials":{"influencersClubApi":{"id":"pfuQoV9XcYUVIeuU","name":"Influencers Club - Gjorgji"}},"typeVersion":1},{"id":"8cd8d225-53e5-4e69-bd3b-d26d8e02de1c","name":"Enrich by Handle (Full)","type":"n8n-nodes-influencersclub.influencersClub","onError":"continueErrorOutput","position":[2752,1472],"parameters":{"handle":"={{ $json.profile.username }}","platform":"={{ $('Normalize').item.json.main_platform }}","resource":"creator","operation":"enrichByHandle","tiktokFilters":{},"twitchFilters":{},"twitterFilters":{},"youtubeFilters":{},"onlyfansFilters":{},"instagramFilters":{},"additionalOptions":{}},"credentials":{"influencersClubApi":{"id":"pfuQoV9XcYUVIeuU","name":"Influencers Club - Gjorgji"}},"typeVersion":1},{"id":"098c57ea-8a56-417c-85a4-5e332b7ca20b","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[2288,1456],"parameters":{"options":{},"fieldToSplitOut":"accounts"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"binaryMode":"separate","availableInMCP":false,"executionOrder":"v1"},"versionId":"175fc5f4-affe-40da-ab18-e923debf7731","connections":{"Normalize":{"main":[[{"node":"Filter - Is Creator?","type":"main","index":0}]]},"Split Out":{"main":[[{"node":"Loop Over Items (Lookalike)","type":"main","index":0}]]},"Extract Email":{"main":[[{"node":"Enrich by Email","type":"main","index":0}]]},"Enrich by Email":{"main":[[{"node":"Normalize","type":"main","index":0}],[{"node":"Stop and Error","type":"main","index":0}]]},"HubSpot Trigger":{"main":[[{"node":"Get Contact by ID","type":"main","index":0}]]},"Get Contact by ID":{"main":[[{"node":"Extract Email","type":"main","index":0}]]},"AI Agent (Lookalike)":{"main":[[{"node":"HubSpot — Lookalike Creator","type":"main","index":0},{"node":"Loop Over Items (Lookalike)","type":"main","index":0}]]},"Filter - Is Creator?":{"main":[[{"node":"Find Similar Creators","type":"main","index":0}]]},"Find Similar Creators":{"main":[[{"node":"Split Out","type":"main","index":0}]]},"Enrich by Handle (Full)":{"main":[[{"node":"Normalize Profile (Lookalike)","type":"main","index":0}]]},"OpenAI Model (Lookalike)1":{"ai_languageModel":[[{"node":"AI Agent (Lookalike)","type":"ai_languageModel","index":0}]]},"Loop Over Items (Lookalike)":{"main":[[],[{"node":"Enrich by Handle (Full)","type":"main","index":0}]]},"Normalize Profile (Lookalike)":{"main":[[{"node":"AI Agent (Lookalike)","type":"main","index":0}]]},"Structured Output Parser (Lookalike)1":{"ai_outputParser":[[{"node":"AI Agent (Lookalike)","type":"ai_outputParser","index":0}]]}}} \ No newline at end of file