LinkedIn outreach to 660,000 HubSpot customers

A client sells a plugin that sits on HubSpot. He wanted every HubSpot customer found, enriched, and messaged on LinkedIn. No one sitting on a queue. The book is about 660,000 records.

I started from a blank Airtable. The canvas is Integromat — now Make.com. The LinkedIn work goes through Growth-Hacking.io: employee extract, invite, contact extract, message extract. An email finder was already built on our side. It was not public yet.

660,000 rows, 13 Airtable bases

One base cannot hold this. I split it: HubSpot 1 through 14. About thirteen or fourteen databases. Each LinkedIn account points at a base. Paste a cookie. Paste an Airtable API key. Same messages on every account, or different copy per account.

I talk to Airtable over HTTP, not the native Integromat module. List records and filter by formula. More control. A field on the account sets how many records that run is allowed to touch, so a test can be one company and a live pass can be eight people.

If the account is empty, it fills itself

The scenario starts by looking up an account: cookie, Growth Hacking token, message sequence. Then it asks the leads table whether anything is assigned to that name.

If yes, it invites.

If no, it goes to companies. An HTTP request pulls employees at that domain and filters them by the client’s job-title criteria. If the extract works, it deletes the company row, iterates the people, and writes a new record for each one: profile URL, first name, last name, job title, connection status second, scrape yes. Those rows get assigned to the account that just asked. On the test, HubSpot itself returned 15 people matching the title. Those were test rows. I did not send them.

The test account was Chris. I ran one company, then two invites, then eight. After eight, Chris was empty. The empty path fired, pulled more companies, assigned the new people to Chris, and kept going.

The client was going to start on one account. I still built the multi-account path. I was trying to get to thousands of LinkedIn accounts. Tens of thousands is the same shape: another cookie.

Invite, then four messages over about seven days

Invite is message one. Connection status 2 or 3 means the request went out. Once a day a contact extractor walks who accepted in the last 24 hours, matches personal LinkedIn to the profile URL, and writes connection status 1.

Next run they get message two. The copy lives in a long-text field on the account so newlines stay. The demo line was “Hi {first name}, how are you.” Delay in days is a field. I used two days for message two and four days for message four.

Message two also has a second path for people who were already first-level, so they do not sit forever because they never “accepted today.”

After message two, a message extractor downloads the thread. If any message author is not the account owner, they replied. Stop. If not, send message three, then message four. The gates are: message two exists and three is empty; three exists and four is empty; connection status contains 1.

That is about a seven-day sequence. It is not one run.

Two views: cold outreach is the live queue. Playground is where the client can poke rows without touching the send filters. I also put a replied field on the row and a three-day window on the filter.

The client only adds LinkedIn accounts

The email follow-up sequence was in the brief. The email finder module was ready internally. I said I would release it the next day and wire it in.

What is left after the canvas works is the data: enrich the 660,000 websites, keep only companies on HubSpot, and put enough LinkedIn accounts in the table to chew through the book. Each account that runs out of people goes and finds more. In theory it runs until every HubSpot customer has had a message.

OFM Insider and Automation Academy if you want the communities from this video. Tools and resources are Bento. A one-off session is Calendly. Four sessions is 4x Consultations.

Transcript

Hey guys and so we're just going to start building out a flow for a a client of mine he's asked for a custom flow and we're going to be finding all HubSpot users like enriching the profiles and then just reaching out to them I literally just started this is a brand new Airtable and we're going to start everything from scratch HubSpot 1 and we're just going to one first name so we're going to build like a complete like follow up sequence for him and we will

Also do a email follow-up sequence cool I think this will fine and then if we just do last specific fields and we're just gonna base that off when the message was sent and and then we were making a connections paper okay and then we're going to rename this view to called outreach and we can just make another view called like playground and this is just where like you'd like ed the client can mess around and do whatever they want and it's not going to interfere with

The actual outreach it's a pretty good way to do things so we'll do LinkedIn personal LinkedIn connection status contact the email first name so we're just tidying this up a little bit so we can just start to build Mike out some basic logic here so we could do like connection status does not contain two and connection status does not contain three and message for is empty we can also do like with some reply tracking new custom field type just to make this a little more like

Beautiful we can do do replied, filter with reply tracking is okay three-day window I think is pretty good so that's going to filter out all okay fine let's actually start off with a router and I was going to make this in two separate rows but I think we'll actually just do it all together so we'll run an HTTP request to get the employees working at a company and after that we will run another request find email employees find the email and then sync those back to

Airtable so here we will do and company enrich via growth hacking module actually going to that'll be a response from that and then okay so the reason that we're doing this is because we want to we're going to have a list of like thousands of domains and we're going to enrich and get the employees from from LinkedIn and we want to make sure that like if we're going to try and get multiple employees for every single person we need to go and create them as a

New record so that's what we're going to be doing over here and we're going to delete the original records so as long as a result exists as long as it's managed to extract employees it will delete that record it will iterate however many results we got and this is actually going to be an email finder it's going to create a record with any emails that it finds so that's going to be the first part of the flow and then it will be invite and connect condition

Personal LinkedIn exists connection status does not exist and then it's just going to be update of record and I'm gonna make it so that he can message one and we can give you message for number of days to build a okay and then we can sign I'm just going to change up this search records sure we're going to do this dynamically add a module HTTP make requests going to API we're just doing this Airtable API offers much more flexibility than using Integromat directly it's pretty cool

List records so if you remember earlier we the reason that we left we want this to be dynamic and we made over here yeah I'm going to rename that actually max records number of Records to process number of view is called active account okay and then need some logic over there Airtable what have you got here okay this is fun a little request then oh there we go so it should have returned yeah there we go straight away we want to put that into just tied

It off so then we'll run like that can also be linked in cookie this what's gonna put broken API in here as well just makes easy to manage growth that will be message number one so now you can see like what why we're doing this sort of structure then we can come down here clean that up again message sender API token so now that we've built that like back in structure is just so much faster for us to just keep clicking these and it means that

You don't have to update every single one it means you can add in like multiple different accounts live cookies, not showing and then this is going to be message to so everything can now be managed from Airtable right and then we can clone that down we linked a message three-flowing again it'll be linked in for so I'm just gonna rename these so this will be LinkedIn invitation LinkedIn message to LinkedIn message three then message four cool clean up again and then here we want to add

The ID will be coming from there and currently we're looking at LinkedIn message two so then we'll just put in like the response under linking message to same for message three and message for the message for whose ID okay so and days and it's gonna be last add days and then because we've allowed the client to set the delay here they can now do that in fact we don't even want a delay there we don't want a delay on message - there's gonna be connection status

Okay I'm just going to do these last two whilst I've got that saved and then we put in the delay from there we do make sure they're not equal to and again we're putting in now cool and then we want an and rule on both of these the condition and message to exists and message three does not exist and yeah we need and message three does not exist and message for just for the sake of this it's a little extra barrier but it is actually pointless

Logic now I think about it condition and message for is empty cool save there's nothing there out message for is empty cool and then in order for this to go through we want connection status contain one and status two does not does not contain true okay so that is the general structure of the outreach setup and now it's just a case of actually plugging these into function and I'm just waiting for just waiting for two companies to get back to me so we can actually start

Enriching some website so I'll come back to this a little bit later cool so just to pick up from where we left off one change that I made is added the employee extractor up here and I think we're actually ready to start like running a few tests I'm just gonna add in like a little test account here so if we go and find like a let's just run the item on this lean on this one just one company per launch and Airtable API I'll just put

That in as well so what this means is because we're going to be processing so many records by having by adding the Airtable API it means that like for example here we have HubSpot one but in total there's going to be 660,000 and records that we're enriching so in total there's going to be about thirteen or fourteen databases different there's gonna be HubSpot one through to fourteen and it means that you can assign multiple accounts each to a different Airtable base which is just quite an

Easy way to segment them so by like it's a simple by adding in your account all you would do is paste another cookie for each account that you have you can change the messaging or keep it the same for all of the account and because we've structured the flow like this we're first off it searches for an account and then it will go and find records associated to that account yeah it's just it's just like a really it's a good way to to manage like it's

Infinitely scalable like you could have hundreds of thousands even like that which is actually what I'm sort of working towards currently I'm trying to get up to like now managing thousands of LinkedIn account even like tens of thousands is completely possible as well only yeah it would just be of LinkedIn accounts okay so client isn't coming back so just to run a test like for my LinkedIn account so if we just delete this condition okay yeah so let's just okay that's why that worked okay cool

So it should then return us one record and it should then go and scrape the employees working there and this initial record would actually be deleted and what was our response result object empty job title filter that's why fields okay number of records to process and then let's go it's deleted itself okay well at least that part is work okay cool let's try that again gone for that company for its so it's finding a record and like currently the client is only going to use like

One account in this flow but I think like once he sees it up and burning he's going to want to very quickly be able to manage multiple accounts so I'm just going to build that logic in just so you can do that in future okay what was our response there for okay so we got the records great so now we can start actually building in some logic so we want to put the result object in their email finder we're going to go and put in the

Growth hacking API token LinkedIn cookies and now like you can sort of see how fast it is for us to to do this email finder we haven't released publicly yet actually so I'll be a little bit dirty but this will learn this is I cannot away if you didn't know you can do this website cool okay and then we can just add in the rest of the information from here so profile URL connection status is going to be second first name last name job title link

To it it's going to be the technology / tool can be empty scrape can be yes an account assigned can also be empty let's just leave it like that for now and if we add this in again in company forward slash company called HubSpot for this time when we run okay great yet so it's now working cool so it got us 15 results from HubSpot that much the job title like we're not actually going to use any of these records this is purely just for like

For testing purposes and let's just see why these aren't appearing and that's why okay so I'm going to change this and to not send across the connection requests if I just come over into our playground this is why we have like the different views so we don't need to keep changing the views clear and then this one can also be deleted and if we come over into outreach so we're not going to send over connection request and we're also going to do setup condition result object

Profile URL exists to make sure that we scraped at least one record from there and now the original has been deleted and we now have 15 records from that company that we can reach out to we've got their job titles and yeah I think they're they're essentially ready for for outreach so what we will then do is just for him do this under two different routers okay there's going to be much easier to do it like this and iterator here and then no it needs to

Be here and we're going to ID exists and then this other root of what we will do is if it ever runs out of record condition ID does not exist then we will route that down this part the condition ID that's not exist tidy that up again so I just need to rethink you condition the five and make enough of flow, make another view sorry enrichment filter and filter where personal LinkedIn is empty and LinkedIn can company and scraped is yeah cool so view needs to

Then be changed to enrichment if you do get requests and then from here I'm just gonna run a little example so we just gonna run that to meet your record so it is sort of like killing itself on purpose once it's well I'll actually do is so basically all accounts will always be assigned to someone so name is going to be here and then the assign all of these you can ask them it's going to throw an error and because it can't find any records they're

Going to be routed down here and it's going to find some new records and assign those to Chris which is exactly website currently won't exist actually so that should then go and find us I'm just going to delete these previous ones but it will work with them but we just want to keep this data pretty clean we so basically it is going to look for records in this database if it can't find them it's going to go and scrape them and update it and assign it

To itself and then it's going to delete the original company and just create a load of new records and if it finds if it has leads to reach out to for example if this is run smoothly already then it's going to go ahead and start on the outreach so I just want to change this I'm going to do list records and we want I hope that's why I felt my name yeah okay cool so failed on one parameter what was that failure linkedin company URL fields

Company URL records field okay that's gonna work and it's going to go and add ten records in here that will then actually appear in our outreach flow because currently it's only showing the companies cool so it's adding those in and then if that has worked correctly they've now been assigned to Chris so that is all set up to work correctly as well so now what's going to happen is it's going to go in search for some record and okay and personal LinkedIn exists let's run that

Again good because it's got records it Chris now has records assigned to it as an account it's now going to go and send the connection request to these profiles and it's going to update that has now been done so one of them let's get the output so now we can add connections think this I think everything else we don't really need to be honest I think that's good process one per run any returned us okay that's why I told it to return this one records let's

Just test two this time let's run that so if first connection should go through we can go back into the other of a database HubSpot 1 and if we come into playground so one two people have now received connection requests and we can tell that because they will now have a connection status yet so two and three so they've come through I also forgot we need to update LinkedIn message one message one that we can put in you can fit in the output this is one

That again and we just make I'm just netted in here like personal LinkedIn it's not empty not that it really matters but yeah so this number should now be going down cool and I'm just going to run I'm just gonna go ahead and run like eight records and I just want to make sure that it will go and find more more LinkedIn profile for itself again I'm a hundred percent sure it will but also just partly to give a little like demonstration we've actually got a

First level connection there that we're already connected with which is good because now we can actually test the second part of and it's going to run eight and then it okay some message to is empty which is why that failed to actually we can just go in just to show you how this works as well so the message is actually being sent from here so we need to change that long text so we can put in and just to show you how this works we've put

In like hi first name we can just say that how are you like that I'm just testing so I don't really care and because we're using long text it means it will grab these new lines and it will make sure that they will put onto a new line and then we can put like a two-day delay, Hi first name just following up. Just the message four, four days so it means that like the client can manage everything from here and I would just go so it's

Going to send messages to those cool that message was also sent last should have actually updated in last is not today cool and so that's fine and then now I can run this again if you can see it's run out of records what you should actually do is go down this path and go and find itself more records which is doing directly cool so that is working cool so yeah because Chris went out of records it's now gone on found more records and it's now reassigned

To him so yeah I think that is that is working great next thing that we can do is actually go and do contact extractor I'm not even - okay so then every day once per day it's going to go through and check for contacts and look for associated records so I'm just going to run that just so that we don't waste any time I'm just going to do ID does not exist condition is that it does not contain cool so turn that off sorry that's completely

My fault so and then and that's going to go and check everyone that we've connected with today and then based on the URLs that we get as a response from that we will go and update people to first level connections and then proceed with with follow-up messages set it on once sorry that was very stupid condition linking cookie I'm actually going to remove this part of the flow and we're going to bring it over here so as long as that is empty that's going to run

Cool yeah so that is there we go and we just need to correctly put the output in here which is going to be the result object the same as before we want to do filter by formula and then we're going to do personal LinkedIn matches profile URL and then we're going to do condition ID exists and connection status does not contain one and if that is true then it's going to update that person to a first level connection connection to do this first very good nice

And what we at the end of it because why not so it's going to go on and every day it's going to check who's accepted our connection requests in them first thing they're going to get our message we can do that profile URL and then update of record so there's going to be two different stages where the user can get message two just in case they get missed out okay yeah that's going to work and be patient yeah I think that's all going to work fine

And then what we may actually do need to rewrite that logic and we're going to do a saved it well enough great feature from Integromat I will say so then we're going to do this part is first of let me add another module growth hacking message extractor and we're only we're going to run down this path condition condition message to exists okay so if message to has been sent then we're going to send down this path and we're going to put in growth hacking API LinkedIn

Cookie as always LinkedIn profile URL a number of messages to extract yeah we only want to let's just come back over and we're just going to make sure that it runs on that one record connection status contains one I'm just going to remove that and I just want to download this message history just to put the logic in place it's now been filtered down that path to do is condition the object messages author does not contain and then we need to do does not contain the

Account owner's name that way it will then continue down this path here I've forgot to do something which is we need to say contacts extracted today true save and then the flow and yeah I mean I like we're actually pretty much done now we just need to work on getting all of the actual data into place we're going to work on enriching about 660,000 and websites for this client and we're only interested in reaching out to people using HubSpot but the actual logic is all in

Place you can use like multiple accounts everything is working correctly which is to be deleted, this we changed, used to be change into three let me just okay nice so I'm just gonna go through like the flow now that we've built everything else so to start off with it searches for an account in our database this is an account that we're managing is going to have the LinkedIn cookie it's going to have their messaging sequence so it can be completely customized to each account and it's

Then going to go into our leads database and it's going to look for leads that have been assigned to that account in this scenario match the account name if it doesn't find any leads that match that account name it's going to go and find them it's going to find companies and then it's going to go in and extract their employees based on our clients criteria it's going to delete the original record and it's going to create new records for every single new lead finds then so

And then it's going to find leads and assign it to itself so that part is completely automated after that once it's assigned leads to itself it's going to go and send the connection request as we've done and it's going to go in update our database a connection request has been sent it's then also everyday going to go and extract sorry extract all contacts here and it's going to tell us and who has accepted our connection requests in the past 24 hours and it's going to go

And update their our first level connection next time it runs it will then go and send message number two that we defined in the other Airtable so it will send the custom message whatever follow-up user wants this can be put in here and it will then go and update Airtable that connection to has been sent after connection message to has been sent it will then go and download message history and it will then go before proceeding with follow ups if the user has not replied it

Will go and then proceed to send two different follow ups so obviously there's going to be like delays like on how frequently you run this that's not all happening at once you know this is going to be a flow for about seven days or so but that's all everything is now built in already and the only other thing that I'm going to add is an email finder we've actually built this out within like the the growth hacking module although it's not public yet so like I

Will release that tomorrow and and I'll add that in and then we'll just our client is using so yeah I mean that's that's pretty much most of the flow built I just need to work on some more like management and like testing it is I'm sure that there'll be some issues that come up so I'll just go through like the entire flow but now it's just the case of like enriching websites basically yeah I hope that was quite insightful I hope that you learned something this

Is like this is quite a clean flow I like it I like it a lot actually and the fact that it goes and finds its own leads as well it's going to be like a hundred percent automated for for the client the only thing he needs to do is make sure he has enough accounts in here to get through like 600,000 leads but yeah really really interesting flow super clean I like it a lot and yeah any questions as always please feel free to leave a comment