# How I manage Google, Meta, Reddit and LinkedIn ads with Kilo Desktop

> Source: <https://blog.kilo.ai/p/how-i-manage-google-meta-reddit-and>
> Published: 2026-10-19 14:11:43+00:00

In May, I [wrote about managing Google Ads with Kilo CLI](https://blog.kilo.ai/p/running-google-ads-from-the-terminal). I had a repository of Python scripts, a few custom skills, and rules for things like campaign naming, tracking and creating campaigns paused. I could ask the agent to build a campaign or audit an account instead of doing the same work in Google Ads Editor.

Since then, I’ve added Meta, Reddit and LinkedIn, and I now work with the repository in [Kilo Desktop](https://kilo.ai/install). It covers accounts for Kilo, [Anaconda](https://www.anaconda.com/), and [All Day AI](https://alldayai.com).

The work is familiar to anyone managing paid media: checking performance, preparing campaigns, changing copy, checking targeting, trying to work out why the registration numbers in the advertising platform don’t match the registration export. There’s just more of it across more accounts.

I didn’t build all of this upfront. I needed something done, we added a script or extended an existing one, and kept the useful parts for next time. The repository grew around the work.

## Why I moved from CLI to Desktop

I moved to Desktop mainly because of how it organises sessions. When I’m launching the same campaign across a few advertising platforms, I can keep a separate session for each platform and work on several at once. It’s easy to switch between them and pick up the relevant conversation. That becomes useful when one launch involves work in Google, Meta, Reddit and LinkedIn.

I still reach for the CLI when I want to pick up a session remotely from my phone through the [Kilo Mobile app](https://kilo.ai/docs/code-with-ai/platforms/mobile). The Desktop build I’m using doesn’t support that connection yet, so that’s the main reason I keep using the CLI.

I open the repository in Kilo Desktop and work with the agent there. It reads the relevant instructions and scripts, queries the platform APIs, and produces the analysis or report I need.

I don’t have to remember which Python file handles which operation. But the files are still there, and I can inspect what the agent is running.

A typical request might look like this:

Pull last week’s performance for this account. Separate the campaigns that are currently running from historical spend on paused campaigns. Check the conversion definitions before comparing CPA. Don’t change anything.

Or:

Check the targeting on these two LinkedIn campaigns. Show me the actual countries, not what you infer from their names.

These are illustrative prompts, but they’re representative of the work. Some sessions are entirely read-only. Others end with a change to an account after I’ve reviewed what will happen.

The repo still does most of the work behind the scenes. It contains the API helpers, account mappings, skills, reports and history. Desktop is where I work with all of that.

The simplified structure now looks like this:

```
paid-ads/
├── AGENTS.md                 # Rules for working in the repo
├── .kilo/skills/             # Instructions for recurring tasks
├── config/                   # Account mappings
├── scripts/
│   ├── google_ads.py
│   ├── meta_ads.py
│   ├── reddit_ads.py
│   ├── linkedin_ads.py
│   └── ...
├── docs/                     # Setup notes and workflows
├── reports/                  # Dated reports and checks
├── tasks/                    # Campaign assets
└── CHANGELOG.md              # Changes and the reasons for them
```

If you read the first article, the paths have changed a little. `AGENTS.md` is now the main instruction file, and the skills live under `.kilo/skills/`. The basic arrangement is the same: instructions explain how we work, scripts make the API calls, and the results stay in the repo.

## How I choose the model

I usually choose frontier models, depending on the task. If I’m working out a new campaign from scratch, I generally pick the strongest model available. At our level of ad spend, I’m happy to spend an extra $5 or $10 on model usage if it helps get the setup right on the first pass. A mistake in the targeting or conversion event can cost considerably more than that.

The screenshot shows **Auto Frontier**, Kilo’s automatic routing option that prioritises capability. Kilo selects the underlying model, and that selection can change as the available models change. The expanded model picker shows what it is using. [Kilo’s Auto Model documentation](https://kilo.ai/docs/code-with-ai/agents/auto-model) explains how the routing works.

An open-weight model could offer better value for parts of this workflow. [DeepSeek V4.1 Flash](https://huggingface.co/deepseek-ai/DeepSeek-V4.1-Flash) is one candidate: its weights are public, and as of October 2026, [Kilo’s coding evaluations](https://kilo.ai/leaderboard) show competitive results at a lower cost than several leading proprietary models. That makes it worth comparing on tasks such as editing a reporting script or producing a report from existing data.

Those coding results don’t establish that it is better at managing advertising campaigns. The useful comparison here is whether it follows the account rules, catches a wrong conversion definition and produces a correct result with fewer corrections. For a new campaign, my preference is still to pay for the strongest model I can use and review its work before anything goes live.

## Connecting Reddit, Meta and LinkedIn

The Python helpers handle authentication and API requests in this setup. Before they can do that, each platform needs a developer app and access to the right advertising account.

**Reddit.** Open [Reddit Ads Manager](https://ads.reddit.com/) and go to **Business → Developer Portal → Add Apps → Create an app**. You need a business admin with a verified account. Enter the app details and register a redirect URL, which is where Reddit sends you after authorisation. Save the app ID and secret. This app connects to the **Reddit Ads API**. Follow the OAuth authorisation flow with `adsread` for reporting and `adsedit` if the scripts will change campaigns. The authorising user also needs access to the intended ad account. Reddit documents [app creation](https://ads-api.reddit.com/docs/v3/guides/quick-start/create-dev-app) and [authentication](https://ads-api.reddit.com/docs/v3/guides/quick-start/authenticate) separately.

**Meta.** Create an app in [Meta for Developers](https://developers.facebook.com/apps/) and enable the **Marketing API**. For an ongoing internal integration, use a system user in the relevant business portfolio: open [Business Settings](https://business.facebook.com/settings/) and go to **Users → System Users**. Assign the app and the ad accounts it should access, then generate a token for that app. Use `ads_read` for reporting and `ads_management` for campaign changes. Creating ads can also require access to the Facebook Page or Instagram identity used by the creative. If the app manages other people’s ad accounts, it needs the relevant Advanced Access permissions. [Meta’s official API setup guide](https://www.postman.com/meta/facebook-marketing-api/collection/0zr4mes/facebook-marketing-api-mapi) explains the token and permission requirements.

**LinkedIn.** Create an app in the [LinkedIn Developer Portal](https://www.linkedin.com/developers/apps), associate it with your company’s LinkedIn Page and complete the Page verification. Under **Products**, request the **Advertising API** and complete its access form; LinkedIn reviews the application before granting access. Under **Auth**, register your redirect URL and use `r_ads` to read account information, `r_ads_reporting` for performance data and `rw_ads` for changes. Authorise through a LinkedIn member with the appropriate Campaign Manager account role. App approval and account access are separate requirements. LinkedIn’s [setup guide](https://learn.microsoft.com/en-us/linkedin/marketing/quick-start) and [permission reference](https://learn.microsoft.com/en-us/linkedin/marketing/increasing-access) cover both. If your app has Development access, add the ad account under Products → View Ad Accounts → Add Ad Account.

The helpers keep tokens and app secrets in local files excluded from Git. After authorisation, I check which accounts the connection can actually reach and save the intended account ID before using it for campaign work.

## Keeping accounts separate

Each platform has its own API and its own slightly annoying requirements. Once access is working, though, adding a useful operation is usually manageable.

Google still has the most extensive tooling because I started there. Meta has reporting and campaign-creation workflows. Reddit has account inspection and a campaign launch workflow. LinkedIn is mainly reporting, with specific scripts for changes I’ve needed.

They don’t all support the same operations. I haven’t built a generic campaign editor for every platform, and there hasn’t been a reason to.

The more important change was making the scripts account-aware.

With one Google Ads account, a customer ID in an environment variable was enough. With several advertisers, that’s an easy way to make a very expensive mistake. Some credential connections can access more than one account, so having valid credentials doesn’t establish that you’re in the right place.

Before a live request, the agent has to identify the platform, advertiser, credential connection and account ID.

Recently, I asked about a campaign under the wrong advertiser. The agent checked that account, couldn’t find it, and we confirmed that it belonged to Kilo before making any changes. A small correction in the conversation, but exactly the sort of thing I want caught before a script starts updating ads.

Older scripts also need checking. Something written six months ago for a specific Kilo campaign may have hard-coded IDs or assumptions that make no sense for Anaconda. I don’t want the agent treating every Python file in the repository as a reusable tool just because it runs.

## A recent Reddit launch

One of the campaigns we launched through this setup was for Kilo Desktop on Reddit.

It had one campaign, one ad group, four image posts and four ads. Alongside the copy and images, we needed to check the communities, geography, conversion event and audience expansion setting.

The agent prepared the payloads so I could review the settings before creation. The delivery objects were created paused, checked, and then activated after approval.

There was an API problem partway through. Reddit required a `start_time` for the ad group, although it wasn’t listed among the required fields in the documentation we were using.

By that point, the paused campaign already existed. Running the whole thing again from the beginning could have created a duplicate. We inspected the account, confirmed what had been created, added the missing field and resumed.

That experience went back into the helper and its documentation. Next time, the start time is already handled, and there’s a recovery path if something fails after the first object is created.

The final check also showed the ads as configured active but still processing. I mention this because an API accepting a request doesn’t mean the ads have started serving. Review and processing states still need checking, just as they do when you create the campaign manually.

## Checking what’s actually configured

A less involved example was a LinkedIn geography correction.

One campaign had EEA in its name but was targeting the US and Canada. We checked the actual targeting and updated it to the intended countries.

The change was limited to geography. Budgets, creatives and the other settings stayed as they were, and the script read the campaign back afterwards to verify that.

These are the sorts of checks I find useful across platforms. Campaign names help me organise an account, but they’re not evidence of how it’s configured.

## Reporting takes more explanation than campaign creation

Creating ads is reasonably straightforward once the settings are agreed. Reporting is where I spend more time checking what the numbers mean.

For All Day AI, for example, I’ve been combining Google, Meta and Reddit data with the actual attendee export. That involves cleaning test and internal registrations, applying the same date cutoff, checking UTMs, and comparing the resulting registration counts with what each platform reports.

The counts don’t necessarily match, and I don’t expect them to.

Several platforms may claim the same registration. A registration record may have no usable source. Some UTMs contain campaign IDs, others contain names, and occasionally a tracking macro turns up as literal text instead of the value it was supposed to insert.

The report needs to leave those problems visible. I don’t want the agent to tidy everything into a single conversion total that looks convincing but means very little.

For the same reason, I keep platform-attributed registrations separate from registrations attributed through the attendee export. Neither is automatically a complete account of what caused someone to register.

This was already part of my Google Ads workflow, but it matters more when comparing channels. A LinkedIn page view, a document interaction and a completed registration can all appear in reports as positive results. They’re not interchangeable.

The agent is useful for pulling the data, joining it, checking totals and spotting inconsistencies. I still need to decide whether the evidence is good enough to change anything.

A Reddit creative getting encouraging clicks might deserve another week of testing. That doesn’t mean it deserves a larger budget.

## The rules have become more specific

The first article included rules like “preview before execution” and “create campaigns paused”. Those still apply.

As the repository has grown, I’ve had to be more precise about them.

For a change, I want to see the account, the exact objects being changed, and what the script will do. Activation and budget changes need explicit approval. After execution, the script should query the account again and check the result.

I’ve also stopped using “dry-run” as shorthand for “nothing happens”.

Some dry-runs are offline payload checks. Others query live accounts or send API validation requests. They can consume quota and write local reports even though they don’t change the ads. The documentation needs to say which kind of preview a script performs.

Where possible, the checks belong in the script itself. If a script is only intended for Kilo, it should refuse to run against another account. If it needs an execution flag, leaving out that flag should prevent the write.

## What I keep from each session

The scripts are useful, but so are the notes around them.

If an API rejects a field, we document the accepted format. If an account uses a particular tracking setup, that goes into its instructions. If we change targeting halfway through a week, the date belongs in the report.

That saves me from explaining the same thing in the next session, or wondering why we made a change three weeks ago.

I do have to distinguish those notes from current account state. A saved report tells me what was true when it was produced. Before changing a campaign, we query it again.

This is probably the biggest difference from using a chat window on its own. The useful output doesn’t end with the conversation. It becomes a script I can run again, a report I can refer to, or an instruction the next session can use.

## Where this leaves the day-to-day work

I still open the advertising platforms. Sometimes I need to inspect how a creative looks, check something the API doesn’t expose, or work through a platform-specific setup screen.

But I no longer need to start every task there.

I can ask for a report across several accounts, investigate a targeting problem, or prepare a campaign in Kilo Desktop with the relevant scripts and account history available in the same place. I review the proposed changes and approve the ones I want.

The first version of the repository was mostly about saving clicks in Google Ads. Now I use it for a much larger share of the job, particularly the reporting and checking that sit between the platforms.

And when Monday reporting comes around, I can spend more of the time reading the numbers rather than exporting them.
