<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zain Khan</title>
    <description>The latest articles on DEV Community by Zain Khan (@zainkhanx10).</description>
    <link>https://dev.to/zainkhanx10</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3986056%2F943d1c18-86f7-4f49-a2a1-5c2fc93882cc.jpeg</url>
      <title>DEV Community: Zain Khan</title>
      <link>https://dev.to/zainkhanx10</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zainkhanx10"/>
    <language>en</language>
    <item>
      <title>I Built a Workflow That Watches Congress Members' Stock Trades in Real Time</title>
      <dc:creator>Zain Khan</dc:creator>
      <pubDate>Tue, 28 Jul 2026 11:19:20 +0000</pubDate>
      <link>https://dev.to/zainkhanx10/i-built-a-workflow-that-watches-congress-members-stock-trades-in-real-time-163f</link>
      <guid>https://dev.to/zainkhanx10/i-built-a-workflow-that-watches-congress-members-stock-trades-in-real-time-163f</guid>
      <description>&lt;p&gt;Congress members are required to disclose their stock trades, but "disclosed" doesn't mean "easy to find." One source is a raw SEC Atom feed. The other is a government site that occasionally hands you a PDF where the actual trade details are buried in a fixed-width table with no clean structure. Nobody's checking either of these by hand every 45 minutes, so nobody catches a new filing until it's already old news.&lt;/p&gt;

&lt;p&gt;I built a workflow that does check, every 45 minutes, pulling from both sources directly, enriching the raw filings with actual transaction data, and firing off an email the moment something genuinely new shows up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhbdhb6nvzx6uf44dgzn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhbdhb6nvzx6uf44dgzn1.png" alt=" " width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built entirely on n8n, pulling straight from SEC EDGAR and House.gov, with results logged to Google Sheets and alerts sent through Gmail.&lt;/p&gt;

&lt;p&gt;The interesting part of this one isn't the orchestration, it's the data access. Both SEC EDGAR and House.gov actively push back against generic scraping. SEC EDGAR returns a 403 to any request without a declared, compliant User-Agent, that's their actual fair-access policy, not a bug. House.gov's disclosure ZIPs behave similarly with generic scraping tools. So instead of routing these requests through a scraping service that can't set custom headers, this workflow calls n8n's built-in HTTP helper directly inside Code nodes, with a real User-Agent string identifying the tool and a contact email, exactly what SEC's policy asks for. No trickery, just compliance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;br&gt;
A 45-minute schedule kicks off two parallel fetches: the SEC EDGAR Form 4 Atom feed, and the House.gov disclosure landing page.&lt;br&gt;
On the House side, a code step scrapes the current year's ZIP archive URL out of the landing page HTML, downloads it as raw binary (again via the built-in HTTP helper, since &lt;strong&gt;ScrapeUnblocker&lt;/strong&gt; 403s on binary files), and decompresses it.&lt;br&gt;
The decompressed archive gets parsed for Periodic Transaction Reports specifically, filtering by FilingType: P, whether the underlying file is XML or tab-delimited text.&lt;br&gt;
On the EDGAR side, the Atom feed gets parsed for Form 4 filings, keeping only the reporting person's entry and dropping the duplicate issuer-side row that the feed also includes.&lt;br&gt;
Both sources merge into one shared schema, then get checked against a running list of filing IDs already logged in Google Sheets. A recency gate also drops anything older than 20 days, so the very first run doesn't treat the entire historical archive as "new."&lt;br&gt;
Genuinely new filings get enriched. For EDGAR, that means fetching the filing's own directory index, locating the ownership XML, and parsing out real transaction data, shares, price, dollar value, deduping identical legs that option exercises tend to double-list. For House filings not covered by the bulk XML, the workflow downloads the actual PTR PDF and extracts trade rows straight out of the PDF text with pattern matching, since the PDF-extraction step wipes out all the upstream fields it would otherwise rely on.&lt;br&gt;
Everything gets logged to Google Sheets, and if anything new made it through, an email alert goes out with the details.&lt;br&gt;
The part worth calling out&lt;/p&gt;

&lt;p&gt;The PDF parsing step is the most fragile part of this by design, and the code says so honestly in its own comments: it's best-effort, and a scanned (non-text) PDF will yield nothing. That's a reasonable tradeoff. Government PDFs aren't guaranteed to be clean, and building a workflow that fails loudly on bad input is far better than one that silently fabricates data. The dedup logic against Google Sheets, plus the recency gate, is what keeps this from becoming an alert-spam machine on day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting it up yourself&lt;/strong&gt;&lt;br&gt;
Point the schedule trigger at whatever check interval works for you (45 minutes is a reasonable default for filings that don't post more than a few times a day).&lt;br&gt;
Edit the USER_AGENT string in both the EDGAR fetch and enrichment code nodes to include your real contact email, SEC requires this, and it's a one-line edit.&lt;br&gt;
Connect Google Sheets for the seen-filings log and the trade log itself.&lt;br&gt;
Connect Gmail (or swap in Slack, Telegram, whatever fits your workflow) for the alert step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbjpadlwt5292eh9gb54w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbjpadlwt5292eh9gb54w.png" alt=" " width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final thought&lt;/strong&gt;&lt;br&gt;
Public disclosure only means something if someone's actually watching it. Most of these filings sit in feeds and PDFs that are technically public but practically invisible unless you're checking constantly. Pulling directly from the source, respecting each site's actual access policy instead of routing around it, is what makes this the kind of workflow you can leave running unattended and trust.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>api</category>
    </item>
    <item>
      <title>I Built a Lead Qualification Pipeline That Scores, Summarizes, and Emails Leads Automatically</title>
      <dc:creator>Zain Khan</dc:creator>
      <pubDate>Wed, 22 Jul 2026 12:28:11 +0000</pubDate>
      <link>https://dev.to/zainkhanx10/i-built-a-lead-qualification-pipeline-that-scores-summarizes-and-emails-leads-automatically-4bdh</link>
      <guid>https://dev.to/zainkhanx10/i-built-a-lead-qualification-pipeline-that-scores-summarizes-and-emails-leads-automatically-4bdh</guid>
      <description>&lt;p&gt;A new lead lands in your spreadsheet. Someone still has to read it, decide if it's worth chasing, write a summary for context, and draft an email that doesn't sound like a template. Multiply that by every lead your forms bring in, and "follow up quickly" quietly becomes the bottleneck.&lt;/p&gt;

&lt;p&gt;So I automated the qualification and the outreach both. The moment a new row hits the sheet, the lead gets scored, and only the ones worth pursuing get summarized, drafted into a personal email, sent, and logged back with the full paper trail. &lt;a href="https://n8n.io/workflows/17279-qualify-leads-and-send-outreach-emails-with-google-sheets-cometapi-and-gmail/" rel="noopener noreferrer"&gt;Grab the workflow from here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmsrlnia5ra8wpwgb9b1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmsrlnia5ra8wpwgb9b1o.png" alt=" " width="799" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built on n8n, using CometAPI for every AI step, scoring, summarizing, and drafting the outreach email.&lt;/p&gt;

&lt;p&gt;Using one API for all three steps keeps the pipeline simple: three prompts, one credential, no juggling separate provider keys or response formats across nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;br&gt;
A Google Sheets trigger fires the moment a new lead row is added.&lt;br&gt;
CometAPI scores the lead from 1–10 based on name, company, and message, returning the number plus a short reason.&lt;br&gt;
A Code node extracts the numeric score with a regex match, falling back to 0 if nothing parses, so a slightly off-format response never crashes the run.&lt;br&gt;
An IF node checks the score against a threshold (7 and above, in this case).&lt;br&gt;
If it qualifies: CometAPI summarizes the lead's needs and how they found you, then drafts a short, friendly outreach email under 120 words with a clear call to action, which gets sent straight through Gmail.&lt;br&gt;
Either way, the lead is logged to a second Google Sheet, name, email, company, message, score, summary, and the email draft, matched and updated by email address, so re-processing the same lead never creates a duplicate row.&lt;/p&gt;

&lt;p&gt;New row → scored → qualified or skipped → summarized, drafted, and emailed if it clears the bar → logged either way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it's worth copying&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It filters before it spends effort. Only leads that clear the threshold get the summary and email steps, so CometAPI calls (and your team's attention) go where they're actually justified.&lt;/li&gt;
&lt;li&gt;It fails safely. The score extraction never throws on a malformed response, it just defaults low instead of breaking the workflow.&lt;/li&gt;
&lt;li&gt;It's a real paper trail, not just an inbox. Every score, summary, and draft is logged back to Sheets, so nothing about a lead's journey is a mystery later.&lt;/li&gt;
&lt;li&gt;Setting it up yourself&lt;/li&gt;
&lt;li&gt;Point the Google Sheets trigger at your leads sheet.&lt;/li&gt;
&lt;li&gt;Add your CometAPI credentials to the scoring, summarizing, and drafting nodes.&lt;/li&gt;
&lt;li&gt;Set your qualification threshold on the IF node.&lt;/li&gt;
&lt;li&gt;Connect Gmail for outreach, and point the final Sheets node at wherever you want results logged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want a different threshold, a longer email, or an extra qualification factor like budget or timeline? It's a prompt or a condition edit, nothing structural changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fztet6x39bbmqfhqdy66u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fztet6x39bbmqfhqdy66u.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final thought&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lead qualification doesn't need a human in the loop for every single row, it needs one for the leads that matter. Pairing n8n's branching logic with CometAPI's scoring and drafting turns "someone should follow up with this" into something that already happened by the time you check your inbox.&lt;/p&gt;

</description>
      <category>lead</category>
      <category>ai</category>
      <category>automation</category>
      <category>cometapi</category>
    </item>
    <item>
      <title>I Turned My Blog Into a Podcast Without Recording a Single Word</title>
      <dc:creator>Zain Khan</dc:creator>
      <pubDate>Mon, 20 Jul 2026 13:00:52 +0000</pubDate>
      <link>https://dev.to/zainkhanx10/i-turned-my-blog-into-a-podcast-without-recording-a-single-word-akm</link>
      <guid>https://dev.to/zainkhanx10/i-turned-my-blog-into-a-podcast-without-recording-a-single-word-akm</guid>
      <description>&lt;p&gt;Not everyone wants to read your blog. Some people want to listen to it on a walk, during a commute, or while doing dishes. Turning written content into audio is one of the highest-leverage things you can do for reach, but recording, editing, and publishing narration for every single post is its own part-time job.&lt;br&gt;
So I automated the entire pipeline. Now, the moment I publish a new blog post, it's rewritten for the ear, narrated, and embedded back into the article as a playable audio player, with zero manual work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's exactly how it works&lt;/strong&gt;&lt;br&gt;
and how to set up the same thing for your own blog. If you'd rather skip ahead, &lt;a href="https://n8n.io/workflows/17097-create-narrated-blog-audio-from-rss-with-google-gemini-smallestai-and-wordpress/" rel="noopener noreferrer"&gt;Grab the workflow from here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This runs on n8n, using Google Gemini to rewrite the article for spoken word and Smallest.ai to turn that script into natural-sounding audio.&lt;br&gt;
The rewrite step matters more than people expect. A blog post written for the eye is full of things that sound terrible read aloud — bullet points, headings, stray URLs, abbreviations. So instead of just piping raw text into a TTS engine, this workflow rewrites it into something that actually sounds like a person talking, then hands it to Smallest.ai, which is what makes the final audio sound like a real narration instead of a robotic reading of a web page.&lt;br&gt;
How the workflow actually works&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9rfrq0jsok9bicay32x2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9rfrq0jsok9bicay32x2.png" alt=" " width="798" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch the RSS feed&lt;/strong&gt; the workflow polls your blog's RSS feed on a schedule. The moment a new post shows up, it kicks off.&lt;br&gt;
&lt;strong&gt;Strip it down to clean text&lt;/strong&gt;, a code step strips out all the HTML, formatting, and leftover markup, leaving just the raw article text to work with.&lt;br&gt;
&lt;strong&gt;Rewrite it for the ear&lt;/strong&gt;, a Google Gemini agent rewrites the post specifically for narration: bullet points become flowing sentences, numbers and abbreviations are spelled out, stray captions and credits are removed, and it adds a natural spoken intro and outro. The result reads like a script, not an article.&lt;br&gt;
&lt;strong&gt;Synthesize the narration&lt;/strong&gt;, that script is sent to Smallest.ai, which generates a clean MP3 narration of the piece.&lt;br&gt;
Host and embed the audio, the audio file is uploaded to Google Drive, made publicly accessible, and an audio player is automatically embedded at the top of the original WordPress post, so readers can either read or listen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3o5hydy0ktcd7gikaucx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3o5hydy0ktcd7gikaucx.png" alt=" " width="799" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New post published&lt;/strong&gt; → rewritten, narrated, hosted, and embedded, all before you've finished your coffee.&lt;br&gt;
Why this setup is worth copying&lt;/p&gt;

&lt;p&gt;It multiplies your content without multiplying your effort. Every post you already write becomes an audio piece for free.&lt;br&gt;
It sounds like narration, not a text reader. The rewrite step is what separates a listenable article from a robotic wall of text being read aloud.&lt;br&gt;
It's a real accessibility win. Not everyone can or wants to read, this gives every post an audio alternative by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting it up yourself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Point the RSS Feed Trigger at your blog's feed URL.&lt;br&gt;
Authenticate Google Gemini inside the LangChain chat model node.&lt;br&gt;
Add your Smallest.ai API credentials to the speech synthesis node.&lt;br&gt;
Connect your Google Drive and WordPress accounts for hosting and embedding.&lt;/p&gt;

&lt;p&gt;Want a different narration tone, a custom intro/outro, or a shorter target length? It's a single prompt edit inside the AI Agent - Rewrite for Audio node.&lt;br&gt;
Final thought&lt;br&gt;
Repurposing content into audio is exactly the kind of task that's valuable but tedious enough that most people never actually do it consistently. Pairing n8n's orchestration with Smallest.ai's speech synthesis turned it into something that just happens in the background, every time you hit publish.&lt;/p&gt;

&lt;p&gt;If you build on top of this, I'd love to see what you add to it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Messaging Delta Tracker: Your Competitor Changed Their Ad Strategy Last Week. Did You Notice?</title>
      <dc:creator>Zain Khan</dc:creator>
      <pubDate>Fri, 03 Jul 2026 18:21:01 +0000</pubDate>
      <link>https://dev.to/zainkhanx10/the-messaging-delta-tracker-your-competitor-changed-their-ad-strategy-last-week-did-you-notice-h47</link>
      <guid>https://dev.to/zainkhanx10/the-messaging-delta-tracker-your-competitor-changed-their-ad-strategy-last-week-did-you-notice-h47</guid>
      <description>&lt;p&gt;Competitors don't announce strategy shifts. They just start running different ads.&lt;/p&gt;

&lt;p&gt;A new headline here. A dropped value prop there. Suddenly they're talking to "enterprise teams" instead of "small businesses," or leading with a price point they never mentioned before. By the time it's obvious enough to notice by eye, it's been true for weeks.&lt;/p&gt;

&lt;p&gt;This build closes that gap. It's an n8n workflow that quietly watches a list of competitors every Monday, pulls their live ads, and asks an AI agent one blunt question: what changed, and should anyone care? Grab the full workflow JSON &lt;a href="https://n8n.io/workflows/16288-track-competitor-ad-messaging-shifts-with-adyntel-openai-and-google-sheets/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and follow along.&lt;/p&gt;

&lt;p&gt;It runs entirely on n8n Cloud, no local install, no docker. Sign in, import the workflow, plug in your credentials, and it's live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&gt;&lt;br&gt;
At the center of this workflow is Adyntel, an ad intelligence node that fetches live ad data from Meta, Google, and LinkedIn using nothing but a company's domain. That alone is useful. The interesting part is what happens next.&lt;/p&gt;

&lt;p&gt;Every week, the workflow saves a snapshot of a competitor's ad copy. The following week, it pulls last week's snapshot back out and hands both weeks, old and new, to an AI agent trained to think like a competitive intelligence analyst. It doesn't just list differences; it interprets them. Did the angle shift from features to social proof? Did a new audience segment show up? Is this a minor tweak, or does it smell like something bigger — a repositioning, a new product, a fundraising push?&lt;/p&gt;

&lt;p&gt;The agent scores its own answer with an urgency rating. Low and Medium urgency shifts get logged quietly for the record. High urgency shifts get pushed straight to Slack, because that's the kind of thing you want to know about before your next planning meeting, not after.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvgp8opkpvkax46r5br1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvgp8opkpvkax46r5br1.png" alt=" " width="799" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What We'll Build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trigger&lt;/strong&gt;: A weekly schedule fires every Monday at 9 AM — no one has to remember to run this.&lt;br&gt;
Load: Pull competitors marked "Pending" from a Google Sheet.&lt;br&gt;
&lt;strong&gt;Collect&lt;/strong&gt;: Fetch this week's live ads for each competitor across Meta, Google, and LinkedIn.&lt;br&gt;
&lt;strong&gt;Normalize&lt;/strong&gt;: Extract clean ad titles and body copy, deduplicated, from three very differently shaped API responses.&lt;br&gt;
&lt;strong&gt;Recall&lt;/strong&gt;: Pull last week's snapshot of the same competitor's ads back out of storage.&lt;br&gt;
&lt;strong&gt;Compare&lt;/strong&gt;: Work out exactly which ad titles are new this week and which ones quietly disappeared.&lt;br&gt;
&lt;strong&gt;Interpret&lt;/strong&gt;: Hand both weeks to an AI agent that names the strategic shift, not just the text difference.&lt;br&gt;
&lt;strong&gt;Store&lt;/strong&gt;: Save this week's snapshot and the AI's delta analysis to Google Sheets.&lt;br&gt;
&lt;strong&gt;Escalate&lt;/strong&gt;: If the urgency rating comes back High, fire a Slack alert immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up the Weekly Trigger and Competitor List&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a Schedule Trigger node set to the cron expression below, every Monday, 9 AM, no manual kickoff required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 9 * * 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right after it, a Google Sheets node reads a competitors tab, filtered to rows where status equals Pending. That filter matters: it's what lets you pause a competitor without deleting their row, just by flipping the status. Each row only needs a domain and a competitor_name, everything downstream keys off the domain.&lt;/p&gt;

&lt;p&gt;A Split In Batches node then loops through competitors one at a time, so a slow API response from one competitor never blocks the rest of the list.&lt;/p&gt;

&lt;p&gt;All three connect to the same &lt;strong&gt;Adyntel&lt;/strong&gt; credential, so you only need to authenticate once. A Merge node (combine by position) brings all three results back together into a single stream before the real work starts.&lt;/p&gt;

&lt;p&gt;From there, a Code node called Extract This Week's Copy does the unglamorous part: Meta, Google, and LinkedIn all shape their ad payloads differently, and this node normalizes all three into one consistent structure, platform, ad title, ad body, while deduplicating anything that shows up twice. If a competitor genuinely has no active ads that week, it doesn't error out; it returns a sentinel row so the rest of the workflow can handle "gone dark" as a real outcome instead of a crash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up the Comparison and the AI Delta Analysis&lt;/strong&gt;&lt;br&gt;
This is where last week meets this week.&lt;br&gt;
A Google Sheets node reads the previous snapshot for the same domain from an ad_copy_snapshots tab, filtered by domain and the prior week's date. A Code node called Build Comparison Context lines the two weeks up side by side and works out exactly which ad titles are new and which ones dropped off, plain set comparison, no AI needed yet.&lt;br&gt;
Then it gets handed to the model.&lt;/p&gt;

&lt;p&gt;Get an API key from OpenAI and add it under Credentials &amp;gt; OpenAI in n8n.&lt;br&gt;
Add an AI Agent node (with an OpenAI Chat Model attached) named AI Agent — Detect Messaging Delta.&lt;br&gt;
Its system message positions it as a competitive intelligence analyst, told specifically to watch for angle changes (features vs. benefits vs. social proof vs. urgency), audience shifts, new product or feature names, value proposition changes, and tone shifts.&lt;br&gt;
The prompt passes in both weeks of ad copy plus the new/dropped title lists, and asks for a strict JSON response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"angle_shift"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"one sentence describing any pivot in core message angle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"new_audiences"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comma-separated audience segments targeted by new ads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"new_value_props"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comma-separated new value propositions or features"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"urgency_signal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"High or Medium or Low"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"urgency_reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"one sentence explaining the urgency rating"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"delta_summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2-3 sentence plain-English summary of what changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"new_ad_titles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"semicolon-separated list of new ad titles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dropped_ad_titles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"semicolon-separated list of dropped ad titles"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdsnpktl0fr3zg82hdfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frdsnpktl0fr3zg82hdfx.png" alt=" " width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Parse Delta Result Code node handles the model's response, including the messy cases where it doesn't return perfectly clean JSON, falling back to regex extraction and keyword-based urgency detection if needed, so one oddly formatted response doesn't take down the run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up Storage and the Slack Escalation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two Google Sheets nodes handle the record-keeping: Prepare Snapshot Rows / Append to Snapshots logs this week's raw ad copy for next week's comparison, and a second append step logs the AI's delta analysis, angle shift, urgency, reasoning, and summary, as its own row.&lt;/p&gt;

&lt;p&gt;An If node (Urgency = High?) checks the AI's rating. Anything Medium or Low loops quietly back to the next competitor. Anything High routes to Format Slack Alert, which builds a message with a color-coded emoji (🔴 High, 🟡 Medium, 🟢 Low), the competitor name, what changed, the new angle, and the specific ads added or dropped — then a Slack node sends it to whichever channel your team actually watches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcl0wgvitj2u7wtv5ai97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcl0wgvitj2u7wtv5ai97.png" alt=" " width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Either path loops back to Loop Over &lt;strong&gt;Competitors&lt;/strong&gt;, and the cycle continues until every competitor on the list has been checked for the week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trigger the Workflow&lt;/strong&gt;&lt;br&gt;
Host it in n8n Cloud and let the Monday schedule handle itself, or click "Test Workflow" to run it on demand the first time. It'll pull your competitor list, gather ads from three platforms, compare this week against last, and, if anything crosses the urgency threshold, land in Slack before you've had a chance to check LinkedIn yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Most competitive intelligence tools tell you that something changed. This one tries to tell you what it means, and only interrupts your day when it actually matters. Point it at a longer competitor list, tighten the urgency criteria to match what your team cares about, or swap Slack for email, the pattern holds either way. Build the version that watches what you can't afford to miss.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
