How To Build a Human-Like Outreach Automation System Using Puppeteer and AI For Any Platform

Problem
Let’s face it—lead generation is a pain.
Whether you're trying to find clients for your freelance gigs, customers for your SaaS, or potential hires for your team, the process can quickly become a time-consuming black hole of manual effort, guesswork, and spiraling costs.
And worse? It doesn’t scale.
So, I decided to flip the script—what if you could build an AI-driven automation workflow that handles the entire process for you, from discovery to outreach?
From finding the right people on the right platform, to crafting a solid outreach message, to actually contacting them—all while mimicking real human behavior and bypassing anti-bot mechanisms like a stealth pro.
In this guide, I’ll show you exactly how I did that—and how you can too.
Steps/Roadmap for a successful platform automation
1. Login: Handling Captchas and Saving Sessions:
Login is one of the most protected areas on any platform, typically safeguarded by CAPTCHA or rate-limiting mechanisms. To bypass these:
🔸 CAPTCHA Solving Tools
You can integrate services that solve CAPTCHAs:
These services offer APIs that you can call with the CAPTCHA image or site key, and they return a token you can use to submit the form.
🔸 Saving Login Sessions
Instead of logging in every time, save the session so Puppeteer loads the browser with cookies and login state already intact.
A general example of launching the browser for
const puppeteer = require("puppeteer");
const axios = require("axios");
(async () => {
const browser = await puppeteer.launch({
headless: false,
userDataDir: './user_data',
args: ['--start-maximized']
});
const page = await browser.newPage();
await page.goto("https://example.com/login", { waitUntil: "networkidle2" });
// Check for CAPTCHA
if (await page.$('.captcha-image')) {
const image = await page.$eval('.captcha-image', el => el.src);
const res = await axios.post('https://2captcha.com/in.php', {
method: 'base64',
key: 'YOUR_API_KEY',
body: image, // you may need to convert src to base64
json: 1
});
const id = res.data.request;
let code;
while (!code) {
await new Promise(r => setTimeout(r, 5000));
const check = await axios.get(`https://2captcha.com/res.php?key=YOUR_API_KEY&action=get&id=${id}&json=1`);
if (check.data.status === 1) code = check.data.request;
}
await page.type('#captcha-input', code); // Adjust selector
}
// Do login if needed...
// await page.type('#username', 'user');
// await page.type('#password', 'pass');
// await page.click('#login');
console.log("Ready with session & captcha solved!");
})();
2. Homepage Detection
After login, ensure that the browser has landed on the homepage. You can either:
Detect based on the URL
Check for unique DOM elements on the homepage
Add some smart waits to simulate natural browsing behavior.
// Wait like a real human using Promise
await new Promise(resolve => setTimeout(resolve, 3000));
if (page.url().includes("/home")) {
console.log("We're on the homepage!");
} else {
// Alternatively use a selector check
await page.waitForSelector(".homepage-banner");
}
3. Scraping with API Interception (Not Just DOM!)
Instead of scraping complex and messy HTML, it's much easier and more reliable to intercept the API requests that the website uses to load its data.
To do this, open Chrome DevTools, go to the Network tab, filter by Fetch/XHR, and look for the API calls the site makes. Once you find the relevant URL, copy it and use it in your Puppeteer script to track and capture those responses directly.
Go to DevTools → Network tab → Filter by fetch → Copy relevant URLs → Use above pattern to track responses.
Here’s how you can intercept and analyze network requests using Puppeteer:
await page.setRequestInterception(true);
page.on("request", (req) => {
if (req.resourceType() === "fetch") {
console.log("Fetching:", req.url());
}
req.continue();
});
page.on("response", async (response) => {
const req = response.request();
if (req.url().includes("/api/target-data")) {
const json = await response.json();
console.log("Captured API response:", json);
}
});
4. Filtering the Scraped Data Using AI
Once you have the raw data, clean and filter it using a prompt to find relevant targets.
Relevancy Scoring (Prompt-based AI)
const { OpenAI } = require("openai");
const openai = new OpenAI({ apiKey: "YOUR_API_KEY" });
async function getRelevancyScore(profile) {
const prompt = `
Analyze this profile: ${JSON.stringify(profile)}
Give a score between 0 to 10 based on how well they match someone looking for web development services.
`;
const res = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
});
return res.choices[0].message.content.trim();
}
Craft a custom message that's uniquely tailored to each client.
async function generateMessage(profile) {
const prompt = `
Write a personalized outreach message for this person: ${JSON.stringify(profile)}
They are a great fit for offering a web development service. Keep the message short and friendly.
`;
const res = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
});
return res.choices[0].message.content.trim();
}
5. Outreach: Human-like Behavior
Many platforms now track your typing speed, mouse movements, and click patterns to detect whether actions are performed by a real human or a bot. To avoid getting flagged, it's important to automate outreach in a way that mimics natural human behavior—this includes randomizing delays, varying message formats, and using typing patterns that look real. This technique is called humanization, and it's key to making your automation appear genuine
Typing Simulation
await page.type("textarea.message", message, { delay: 50 });
Mouse Click Simulation
const button = await page.$("button.send");
const boundingBox = await button.boundingBox();
await page.mouse.click(boundingBox.x + 5, boundingBox.y + 5, { delay: 100 });
Adding random waits between actions also helps:
await page.waitForTimeout(Math.floor(Math.random() * 2000) + 1000);
6. Track and Analyze Responses
After outreach, monitor incoming messages and use AI to classify the response:
async function analyzeResponse(text) {
const prompt = `
Is the following message a positive response to a cold outreach?
Message: "${text}"
Answer with YES or NO.
`;
const res = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: prompt }],
});
return res.choices[0].message.content.trim();
}
You can poll the inbox or listen to incoming messages via selectors and analyze their content using the above function.
Final Words
With this system in place, you’ve built:
✅ A fully automated browser agent using Puppeteer
✅ A login system with persistent session storage
✅ Smart scraping via network/API interception
✅ AI-powered filtering and personalized targeting
✅ Human-like interaction patterns to bypass detection
✅ Lead response tracking to focus on hot prospects
Now, scale it, fine-tune your prompts, analyze what works—and you’ll be able to turn hundreds (even thousands) of cold leads into real, engaged conversations.
If you found this guide helpful, give it a like and feel free to reach out with questions, collaborations, or feedback at shivangsingh2240@gmail.com — I’d love to hear from you! 🙌
Happy Automating!
Subscribe to my newsletter
Read articles from Shivang Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
