- Brand
- Opus Growth
- Category
- Marketing
- Primary Subcategory
- Ad Campaign Analytics & Reporting
Integration details
Description
Opus Growth connects your advertising accounts to ChatGPT so you can run them by talking. Ask for a performance report, change a budget, pause a campaign, add negative keywords, or build a new search campaign, and it happens in your own ad account. Works with Google Ads, Meta, Microsoft Advertising, TikTok and LinkedIn. Search Console, Google Analytics, Tag Manager, Business Profile and YouTube connect alongside them, so you can ask why a campaign is underperforming and get an answer that accounts for the traffic and conversions behind it. You connect each account once with your own credentials, and access stays limited to what you granted. Every change is previewed and confirmed by you before it is applied, and each action is recorded in an audit log you can review.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Ad Campaign Analytics & Reporting
- Secondary Subcategories
- None listed
- Brand
- Opus Growth
- Access
- Account required
- First tracked
- 2026-10-24
- Tool count
- 448
- Market
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Your score is coming
ChatGPT now suggests Plugins on its own when they match a user's request.Your Plugin Discovery Score measures how often yours appears, and it will show here as soon as it’s ready.
What discovery looks like

Get alerts for Opus Growth
Get updates when Opus Growth’s Discoverability Score or category rank changes.
Competing in ChatGPT Ad Campaign Analytics & Reporting
View Category448 tools agents can invoke
Account hygiene audit: finds wasteful keywords and low Quality Score. DATE: period ('today','last_30_days'… or 'YYYY-MM-DD[:...]') overrides days; days=0 = today.
account_audit
ONE-CALL ACCOUNT PICTURE for an ad platform — use it before any account review, health check or "what is going on in my account" answer. For every campaign it joins: what it is (status, whether it is actually serving, type, daily budget, bidding and the platform's own learning status where exposed), WHEN it was created, started and last changed, its age in days, its performance SINCE IT STARTED (lifetime: spend, impressions, clicks, conversions, CPC, CTR, cost per conversion, average daily spend) and over the last `recent_days` full days, plus account totals. platform: google_ads | meta | tiktok | linkedin | microsoft | chatgpt_ads. account = that platform's account id (empty = connected default). include_inactive=false lists serving/active campaigns and any campaign that spent in the lifetime window; true lists every non-removed campaign. Lifetime starts at the earliest campaign start/creation date, capped by how far each platform's reporting API goes back (stated in `lifetime_window`). Meta conversions are reported per action type (leads, messaging_conversations, purchases, registrations, link_clicks) because Meta has no single conversion count. LinkedIn rows are API campaigns = what Campaign Manager calls ad sets. Microsoft's report has no campaign id, so its rows are joined by campaign name. Costs the credits of the underlying list_entities and get_report calls. Read-only.
account_snapshot
GOOGLE ADS ONLY — reads the full content of Google Ads ads (RSA headlines/descriptions, URL, status) together with each ad's AD STRENGTH and Google's own action items for improving it. Filtered by ad_group_id or ad_id. `ad_strength` is the value Google shows in the interface: PENDING, NO_ADS, POOR, AVERAGE, GOOD or EXCELLENT. It answers "is this ad done or is one step left", which a weak-ads list cannot — a list of weak ads tells you what is bad, not whether the rest reached EXCELLENT. `action_items` is what Google itself says is missing on that specific ad ("try including more keywords in your headlines"), so the remaining gap is read rather than guessed; an ad can have all 15 headlines filled and still score low because they repeat each other. customer_id is a 10-digit Google Ads id; for Meta/TikTok/LinkedIn ads use list_meta_ads / list_tiktok_ads / list_linkedin_creatives instead.
get_ad_details
Reads a campaign's CURRENT ad schedule (day/hour blocks + minutes + bid modifier + criterion_id). If campaign_id is empty, covers all campaigns. The 'block' field is ready to paste into set_ad_schedule. Read-only.
get_ad_schedule
Adds extension assets to a campaign — or to ONE AD GROUP when ad_group_id is given. AD GROUP LEVEL: pass ad_group_id (campaign_id may then be left empty; it is resolved from the ad group) and every asset created or linked here is attached as an AdGroupAsset to that ad group only. Google serves ad-group assets INSTEAD of the campaign's assets of the same type for that ad group's ads, so a branch ad group can show its own phone number, WhatsApp chat, sitelinks and callouts while the rest of the campaign keeps the campaign-level ones. To reuse assets already created for one ad group on a second ad group, pass link_asset_ids with the other ad_group_id (no duplicates are created). callouts: short highlights ['Free Shipping',...]. sitelinks: lines in 'text|url' or 'text|url|description1|description2' format. phone_number (+phone_country) adds a call extension. snippet_header + snippet_values add a structured snippet (header e.g. 'Services', 'Brands' — from Google's fixed list). whatsapp_number (+whatsapp_country, whatsapp_greeting, whatsapp_cta, whatsapp_cta_text) adds a MESSAGE extension (BUSINESS_MESSAGE) that opens a WhatsApp chat — all five are required by Google: greeting is the pre-filled first message, whatsapp_cta is one of APPLY_NOW, BOOK_NOW, CONTACT_US, GET_INFO, GET_OFFER, GET_QUOTE, GET_STARTED, LEARN_MORE, and whatsapp_cta_text is the button description (max 30 chars). Only WhatsApp is supported (Facebook Messenger and Zalo need provider data Google does not expose here). prices: PRICE extensions, one line per offering in 'Header|Description|1500 TRY|https://url' format (optional extra '|unit:PER_MONTH'); 3 to 8 offerings are required, headers must be unique and max 25 chars, descriptions max 25 chars. price_type groups them (SERVICES, BRANDS, PRODUCT_CATEGORIES, NEIGHBORHOODS, EVENTS, LOCATIONS, PRODUCT_TIERS, SERVICE_CATEGORIES, SERVICE_TIERS), price_qualifier is optional (FROM, UP_TO, AVERAGE) and price_language must be one of de, en, es, fr, it, ja, nl, pl, pt_BR, ru, sv. IMPORTANT, measured against the live API: Google does NOT support Turkish (tr) or the Turkish lira (TRY) for price extensions, so a TRY account cannot use them — the tool says so instead of failing cryptically. promotions: PROMOTION extensions in 'Target text|discount|https://url' format — discount is '%20' (percent) or '150 TRY' (amount); optional extra '|key:value' segments: code:SUMMER25, min:500 (minimum order amount, mutually exclusive with code), start:2026-08-01, end:2026-09-01, occasion:SUMMER_SALE, lang:tr, modifier:UP_TO. link_asset_ids: comma-separated asset IDs ALREADY in the account's asset library (from list_assets) — links them to the campaign INSTEAD of creating duplicates; the field type is derived from the asset's own type (PROMOTION, SITELINK, CALLOUT, CALL, STRUCTURED_SNIPPET, PRICE, MOBILE_APP, HOTEL_CALLOUT, LEAD_FORM, IMAGE). IMAGE assets (from upload_image_asset) are linked as the Search IMAGE EXTENSION (field type AD_IMAGE) — Google requires at least 300x300 px and accepts 1.91:1 and 1:1 crops. At least one extension type must be provided. confirm=false → dry-run. To VIEW or REMOVE existing extensions, use list_extension_assets and remove_extension_assets. LOCATION (business address, map pin, "Get directions") is NOT an extension type here: location assets are generated automatically from the Google Business Profile link and serve account-wide — inspect or pin them with add_location_assets.
manage_extension_assets
ADD POSITIVE KEYWORDS to a Google Ads ad group (bulk) — the keywords your ads should SHOW for. This is NOT the negative-keyword tool: use add_negative_keyword only to BLOCK traffic. match_type: PHRASE | EXACT | BROAD, applied to every item that does not carry its own. PER-KEYWORD MATCH TYPE: suffix an item with '|EXACT', '|PHRASE' or '|BROAD' and that one overrides the default — keywords=['yeminli tercume|EXACT', 'noter onayli tercume|PHRASE', 'tercume burosu'] adds a mixed set in ONE call, the same suffix syntax add_negative_keyword already uses. Without it a mixed set needs one call per match type. To MOVE keywords between ad groups, add them here on the target ad group and then remove them from the old one with manage_keywords(action='remove'). To pause/enable/re-bid an EXISTING keyword use manage_keywords. confirm=false → dry-run.
add_keywords
Attaches Google Business Profile LOCATION assets (store address, map pin, "Get directions", call-from-map) to the account's ads. In Google Ads, location assets are created AUTOMATICALLY once the Business Profile is LINKED to the Google Ads account, then serve account-wide. This tool: (1) detects whether a linked location asset set (LOCATION_SYNC / Business-Profile location group) exists in the account; (2) if it exists AND a campaign_id is given, pins that asset set to the campaign (otherwise Google already serves it account-wide — nothing to do); (3) if none exists, returns the exact steps to link the Business Profile. confirm=false → dry-run. AD GROUP LEVEL: pass ad_group_id to pin the location asset set to ONE ad group (AdGroupAssetSet) instead of the whole campaign, e.g. a branch ad group that should show only that branch's address. asset_set_id picks a specific location asset set (a location group such as "Bağcılar", from the location_asset_sets list this tool returns); without it the Business Profile sync set is used. NOTE: creating the Business-Profile↔Ads link itself needs Business Profile API access (pending Google approval); until then the customer links it once in the Google Ads UI (~2 minutes).
add_location_assets
Adds SITELINK and/or CALLOUT ad extensions to a Microsoft (Bing) campaign — the extra links and highlights that make the ad taller and lift CTR. sitelinks: lines in 'Display text|https://url' or 'text|url|description1|description2' format (display text ≤25 chars). callouts: short highlight phrases like ['Free shipping', 'Same-day support'] (≤25 chars). Creates them in the account library and attaches them to the campaign in one call. confirm=false = preview, confirm=true applies.
add_microsoft_ad_extensions
Adds keywords to an ad group. match_type: Broad | Phrase | Exact. confirm=false = preview, confirm=true applies.
add_microsoft_keywords
Adds negative keywords to a campaign or ad group. entity_type: Campaign | AdGroup. keywords: a list, or a comma-separated string ("staj, kurs"). match_type: Exact | Phrase (negatives support only these two). confirm=false = preview, confirm=true applies.
add_microsoft_negative_keywords
Adds negative keywords at CAMPAIGN or AD GROUP level (to stop wasted spend) — ONE keyword or a WHOLE BATCH in a single call. BULK (use this whenever there is more than one keyword — one call, one confirmation, one credit): keywords=['ucuz|BROAD', 'iş ilanı|EXACT', 'kariyer'] — each item is 'text' (takes match_type, default PHRASE) or 'text|EXACT' / 'text|PHRASE' / 'text|BROAD', exactly like manage_shared_negative_list. A comma- or newline-separated string is accepted too. Up to 5000 per call. NEVER loop this tool one keyword at a time: the batch goes to Google as a single mutate with partial failure ON, so one bad or duplicate keyword can no longer take the rest of the batch down, every keyword comes back with its own ok/criterion_id/error, and nothing can be silently dropped between hand-made batches. skip_existing=true (default) first reads the negatives already live on that campaign/ad group and skips exact (text + match type) duplicates — repeat daily runs then stay idempotent and do not burn the 10.000-negatives-per-campaign limit. Set false to write them anyway. Give campaign_id to block the term across the whole campaign, or ad_group_id to block it in ONE ad group only — the latter is what cross-negation needs (each ad group serves only its own theme, negating the other groups' core terms inside a single campaign). If both are given, ad_group_id wins. Undo: remove_negative_keyword (bulk: criterion_ids=[...] or keywords=[...]) at campaign level; manage_keywords(action='remove') at ad group level — list_negative_keywords returns the ids. If confirm=false, returns a dry-run preview of the WHOLE batch.
add_negative_keyword
Attaches IMAGES to a Performance Max asset group (required for the campaign to be eligible to run). Each parameter is a list of asset resource_names returned by upload_image_asset. marketing_image (1.91:1 landscape), square_image (1:1 square), logo (1:1). PMax requires at least 1 landscape + 1 square image + 1 logo. confirm=false → dry-run.
add_pmax_images
Adds a website as a property to the connected Search Console account, so a site that was never added (gsc_list_sites does not show it) can be set up from chat. `site_url` is either a domain property ('sc-domain:example.com', covers every subdomain and http/https; recommended) or a URL-prefix property ('https://www.example.com/'). A newly added property is UNVERIFIED: Google only shows its data after ownership is proven, and the verification code is shown only to the signed-in owner in Search Console. Next step after adding: the user opens the property in Search Console (link in the result), picks the DNS TXT method, and gives you the 'google-site-verification=...' value; if the domain's DNS is hosted on Opus Growth, write it with site_dns_records (mode='add', type='TXT') and the user presses Verify. confirm=false previews, confirm=true adds.
gsc_add_site
Adds ANOTHER website to the user's existing server, on its own domain. Use this instead of telling them to buy a second server: one server hosts up to 15 sites, at no extra cost. `domain` is the new site's own domain (e.g. ikincisite.com); `key` is an optional short name used to address the site in later tool calls (defaults to a slug of the domain). confirm=false previews, confirm=true creates it. We take the domain onto our own DNS: the only thing the customer does is change the nameservers (NS) at their registrar to the ones this tool returns — never hand them CNAME/A records. If the domain's zone is already ours (e.g. blog.theirsite.com) there is nothing for them to do at all. Then write the pages with site_write_file(site='<key>', …).
add_site
ADJUSTS conversions you already reported — the refund/cancellation half of the closed loop. RETRACT cancels a conversion that fell through (refund, cancelled order, unqualified lead); RESTATE corrects its value (partial refund, upsell). Without this, Smart Bidding keeps optimizing toward revenue that never actually landed. conversion_action = name or ID. adjustments accepts a JSON array OR one row per line as 'key=value;key=value': • type=RETRACT;order_id=A-991;datetime=2026-08-05 09:00:00+03:00 • type=RESTATE;order_id=A-991;datetime=2026-08-05 09:00:00+03:00;value=1200 Identify the original conversion by order_id (recommended) OR by gclid + conversion_datetime. Fields: type (RETRACT|RESTATE), datetime (REQUIRED = when the adjustment happened), order_id, gclid, conversion_datetime (original conversion time, needed with gclid), value (RESTATE only). confirm=false → preview; confirm=true → applies.
upload_conversion_adjustments
ANIMATE AN IMAGE INTO A VIDEO CLIP (AI motion video): turns one still image into a 5 or 10 second video with real motion (camera push-in, steam rising, liquid pouring, fabric moving, people moving naturally), then sets the headline, logo and call-to-action button on top in real fonts. Use it when the user wants a moving video ad from a product photo or a creative, not just a slideshow (hareketli video, görseli canlandır; animiertes Video; animar imagen; animer une image). For a slideshow of several images use create_video_creative, which is faster and cheaper. Source: creative_id from create_ad_creative (its image without text is used) or image_url (public image URL, e.g. a product photo or upload_image URL). motion: describe only the movement in English or the user's language, e.g. "slow camera push-in, steam rising from the cup" (keep it simple and physical; the product should stay recognizable). duration 5 or 10 seconds. format: story 1080x1920 (default) | portrait 1080x1350 | square 1080x1080; the image is cropped to that shape. headline, cta, logo_url, brand_color, font: optional text layer as in create_ad_creative; leave empty for a clean clip. This runs in the background and takes about 1-4 minutes. It returns a `job_id` immediately: tell the user it is being made, then call creative_status(job_id) after about a minute and again until status is done; the result has `video_url` (MP4) for upload_meta_video or upload_tiktok_video. Uses more credits than images and counts toward the plan's daily and monthly motion-video limits (10 seconds counts twice); not available on the Basic plan. If the job fails, the credits are refunded.
animate_creative
Applies or dismisses Google recommendations. resource_names: comma-separated values from list_recommendations. action: apply | dismiss. apply can make costly changes such as budget increases (subject to the same budget guardrails as set_campaign_budget). confirm=false → dry-run.
apply_recommendation
Lists the account's ASSET LIBRARY ("Öğeler" / Assets) — ALL asset types across the whole account (not just one campaign): sitelinks, callouts, structured snippets, calls, IMAGES, promotions, prices, lead forms, and text assets. Shows each asset's type, a readable label, id, and source (ADVERTISER = you created it, AUTOMATICALLY_CREATED = Google auto). Optionally filter with asset_type (e.g. IMAGE, SITELINK, CALLOUT, PROMOTION). The reply always reports the TRUE total in the account and says when the list was cut short by `limit`, so a capped page is never mistaken for the whole library. include_usage=true also says, per asset, whether it is used by a running ad, only by paused/removed ones, or by nothing at all — that is what to check before any clean-up. NOTE: Google Ads has NO API to delete library assets (the API supports create and update only), so unused assets cannot be removed from here or in bulk; they can only be unlinked from campaigns (remove_extension_assets) or hidden in the Google Ads interface. LOCATION is NOT an asset-library type — location assets come from the Google Business Profile link and are handled by add_location_assets. BUSINESS NAME / LOGO are NOT asset types in Google Ads — they are FIELD TYPES of a TEXT or IMAGE asset, so look for them with list_extension_assets (which reports campaign- and account-level BUSINESS_NAME / BUSINESS_LOGO / LANDSCAPE_LOGO links) and attach them with manage_extension_assets(link_asset_ids=..., link_field_type=...). include_approval=true adds, per asset, its LINK approval status across campaigns and the account — approval_status is ELIGIBLE / PENDING / LIMITED / NOT_ELIGIBLE, with reasons such as ASSET_DISAPPROVED — plus a top-level approval_summary of the disapproved/limited ones. That is how you answer "which sitelinks were not approved" (the ad-level policy report, list_ad_policy_issues, covers ads only and never shows extension/sitelink assets). Read-only.
list_assets
Attaches an existing conversion tracking rule to a LinkedIn campaign so it reports/optimizes for that conversion. conversion_id: the numeric id from list_linkedin_conversions. A MAX_CONVERSION (automated 'Maximum Delivery') campaign REQUIRES a conversion attached before it can go ACTIVE. confirm=false = preview.
attach_linkedin_conversion
ATTACHES an audience to a campaign or ad group (or removes it) — the missing link that makes your audience lists actually do something. Creating a remarketing/customer-match/lookalike list does NOT affect delivery until it is attached to a campaign; until now they were built but never connected. audience = one of THREE different things, and the tool works out which: • YOUR OWN remarketing / customer-match / lookalike list — name or ID from list_audiences. Works at campaign AND ad-group level. • A GOOGLE-DEFINED segment — an in-market, affinity, life-event or detailed-demographic audience, given by its EXACT display name as it appears in reports and in the Google Ads interface (e.g. "Network & Enterprise Security", "Large Employer (250-10k Employees)"), or as customers/…/userInterests/92507. Campaign and ad-group level both work. Two limits come from Google: a detailed-demographic CATEGORY cannot be attached, only a leaf inside it ("Large Employer (250-10k Employees)" works, "Company Size" does not), and life-event segments are refused on Search campaigns — they exist for Display, Video and Demand Gen. NOTE: the criterion_id in an audience report is NOT the segment id — do not pass it here; pass the name. • An AUDIENCE from Audience Manager (the combined audiences Demand Gen uses) — its name, ID, or customers/…/audiences/123. Ad-group level only. DEMAND GEN ad groups accept only an Audience, never a bare list or segment. When you give a list or segment for such an ad group, the tool reuses the audience with the same name or creates one containing it, then attaches that audience. The audience always targets there, so mode does not apply, and exclusions on Demand Gen ad groups are refused by Google. Give campaign_id OR ad_group_id. action: • attach = add the audience as a POSITIVE criterion (observe/bid on it). • exclude = add it as a NEGATIVE criterion (negative=true) → do NOT show ads to this audience (e.g. exclude people who already converted / clicked call/WhatsApp). Works at campaign AND ad-group level. • remove = detach the positive audience criterion. • remove_exclusion = remove a previously excluded audience. (remove/remove_exclusion find the exact criterion by this audience + negative flag, so the right one is removed.) mode (positive attach only): OBSERVATION = don't narrow reach, just report/bid (safe default). TARGETING = restrict reach to only the attached audiences (e.g. a search remarketing / RLSA campaign shown only to site visitors). TARGETING is a setting of the whole campaign or ad group: it narrows delivery to ALL positive audiences attached at that level, and its other targeting restrictions are kept. Empty mode = OBSERVATION for a new audience and leaves the existing setting unchanged. If the audience is already attached, attach with mode=TARGETING just switches the setting, and attach with mode=OBSERVATION switches it back to observation. bid_modifier: optional bid multiplier for a POSITIVE audience, e.g. 1.2 = +20% (invalid for exclude; 0 = none). confirm=false previews.
manage_audience_targeting
Takes a consistent backup of the website's database and stores it on the server under /data/backups. Uses a transaction-consistent dump, so the site keeps working while it runs and no table is locked. Leave `database` empty to back up everything. The reply lists the backups that exist afterwards, newest first — feed one of those file names to site_db_restore. A nightly automatic backup already runs; this tool is for taking one right before a risky change.
site_db_backup
Reads a background command started by site_run_command(background=true): whether it is still running, what it has printed so far, and the exit code once it ends. job = the id that call returned. Call it again after a while for long installs; the output is the tail of the job's log, so a huge npm log does not flood the conversation. Read-only: it never starts or stops anything.
site_command_status
Inspects the Google index status of MANY URLs in one call — a batch wrapper over gsc_url_inspect for site-wide crawl-freshness audits (which URLs Google recrawled since a content change, which are indexed, which were never crawled). Returns a compact row per URL — page_url, verdict, coverage (coverageState), last_crawl, indexing, google_canonical — deliberately WITHOUT the rich-results / mobile detail so the whole table stays within the result-size limit. page_urls is a list of full URLs (a comma/newline-separated string is also accepted). At most `limit` URLs per call, hard-capped at 20, because Google's URL Inspection API is quota-limited (~2000/day and 600/min per property); if a quota or rate error is hit mid-batch the tool STOPS and reports how many rows it managed. site_url must be a verified property. Same limit as gsc_url_inspect: requesting (re)indexing is not possible through any API.
gsc_inspect_urls
Shows your current plan, remaining monthly operation quota and trial dates.
get_billing_status
Excludes IP addresses from a Google Ads campaign by adding them as IP exclusion (negative IP_BLOCK) campaign criteria, for example addresses that produce repeated invalid clicks. ips = comma-separated IPv4/IPv6 addresses, at most 200 per call; Google Ads allows up to 500 IP exclusions per campaign. confirm=false returns a preview, confirm=true applies. Use unblock_ip_addresses with the criterion ids from list_ip_exclusions to undo.
block_ip_addresses
BUDGET PACING — projects this month's spend against the daily budget; flags campaigns that will OVERspend (over) or UNDERspend (under) by month-end. threshold_pct: deviation threshold (%). pace_pct = actual daily average / daily budget. READ-ONLY.
budget_pacing_alerts
Applies the SAME find/replace to MANY WordPress posts/pages in one call, with a mandatory dry-run. wordpress_update_post's replace works well but takes a single id, so fixing the same defect on 11 pages meant 11 calls; this does it once, and its confirm=false PREVIEW shows every page that would change and HOW MANY times before anything is written, so an unintended broad match is visible first. Choose the target pages either with ids=[...] (get them from wordpress_search_content) or with a search filter (search=..., search_in/regex/type/status like wordpress_search_content). replace=[{"find":"old","with":"new"}] — same schema and safety as wordpress_update_post: a missing "with" is refused, never treated as a delete. match="normalized" (top-level or per entry) treats invisible characters (non-breaking space, smart quotes, long dashes) as their plain equivalents. DESTRUCTIVE: confirm=false previews per-page counts and writes NOTHING; confirm=true applies. Elementor/Divi pages whose visible text is not in post_content are reported as skipped, not silently missed. The search filter fetches every post one by one (~1 s each), so on a large site one call stops scanning after about 100 seconds and returns what it found so far with partial=true and next_offset; call again with offset=next_offset (same other arguments) to continue. For big sites it is faster to run wordpress_search_content first and pass its ids here.
wordpress_bulk_replace
Reads all information for a business location: name, address, phone, website, description, categories, business hours, THE SERVICES THE BUSINESS OFFERS, the Maps link, the Google place ID (`place_id`) and the direct "write a review" link (`review_uri`, ready for a QR card or a message to customers). location = a value from gbp_list_locations OR a business name/domain ('Altes Diş' / 'altesklinik.com') — auto-matched to the correct location. `services` is the business's OWN service list (Google calls it serviceItems): each entry has a name, an optional description and an optional price, plus `kind` = "structured" (one of Google's predefined service types for the category) or "free_form" (a custom service the business typed itself). `services_count` is the true total; the list is capped at `services_limit`. NOTE ON EMPTY RESULTS: `services: []` means the business really has NOT entered any services — it is NOT a tool limitation. Do NOT infer the service list from `categories`: the category objects carry a Google CATALOG of what is *available* for that category, which is why the raw catalog fields are deliberately not returned here. `google_updates` is the "Google updates" badge you see in the Business Profile Manager: when Google (or a member of the public) proposes a change to the listing, `pending` is true and `changes` shows each affected field with the CURRENT value next to the one Google suggests — so you can tell a harmless tweak from a name or address change the owner must react to. Accepting or rejecting a suggestion has no API endpoint; it is done in the Business Profile Manager, though re-writing the correct value with gbp_update_location also overrides the suggestion.
gbp_location_details
Lists all business locations across the connected Google Business Profile accounts (name, address, phone, website). Pass the returned `location` value to other gbp_* tools.
gbp_list_locations
Google Business Profile PERFORMANCE insights — how customers find and act on the listing on Google Search & Maps: impressions (search + maps), phone CALLS, direction requests, website clicks and bookings, totalled over the last `days` (default 30, max 540). by_day=true also returns `daily`: one row per day with search_impressions, maps_impressions, calls, direction_requests, website_clicks and bookings, for trend charts. Uses Google's current Business Profile Performance API. `messages` is ALWAYS 0 and is kept only for backward compatibility: Google shut Business Profile messaging down on 31 July 2024, so it is a dead metric, NOT a feature waiting to be switched on — never advise the user to "turn messaging on". `bookings` is different: Reserve with Google is still live, so a 0 there IS a real gap. location = a gbp_list_locations value OR a business name/domain ('Altes Diş' / 'altesklinik.com') — auto-matched.
gbp_insights
The actual SEARCH TERMS people typed on Google Search & Maps before the business listing appeared ("searches used to find your business" in the Business Profile dashboard) — the only source that shows WHICH queries a location ranks for locally, so you can see which service or category is missing. Returns the terms ranked by impressions plus a summary. Google gives an exact count only for high-volume terms; everything else is reported as "fewer than N" and is counted, not guessed. Data lags ~2 months and goes back ~18 months. location = a gbp_list_locations value OR a business name/domain — auto-matched. For impressions/calls/directions totals use gbp_insights instead.
gbp_search_keywords
Reads and sets the SOCIAL MEDIA LINKS on a Google Business Profile: Instagram, Facebook, X (Twitter), LinkedIn, YouTube, TikTok, Pinterest, WhatsApp and the appointment link. Call with `location` alone to READ what is currently published. WHY A SEPARATE TOOL: these live in the location's ATTRIBUTES resource, not in the location body, so gbp_update_location cannot see or change them. `links` = comma-separated `network=url` pairs, e.g. `instagram=https://instagram.com/acme, youtube=https://youtube.com/@acme`. Accepted network names: instagram, facebook, twitter (or x), linkedin, youtube, tiktok, pinterest, whatsapp, appointment. `remove` = comma-separated network names to clear. Only the networks you name are touched; every other attribute on the listing is preserved. Google allows a different attribute set per business CATEGORY, so each network you pass is checked against what Google permits for that listing first and an unsupported one is reported instead of being silently dropped. confirm=false → preview of the exact before/after.
gbp_social_links
Lists a business location's Google reviews (stars, reviewer, text, date, reply status, and when the reply was written) + the average rating and how many are still UNANSWERED. Each answered review carries `replied_at`, so reply SPEED (created → replied_at) is measurable. gbp_reply_review posts a reply. Large profiles: use summary_only=true for just the counts, only_unanswered=true to see just the ones needing a reply, and offset+limit to page (the answer tells you next_offset). Order is most recently UPDATED first and a reply updates a review, so unanswered reviews collect at the END of the list; use only_unanswered=true instead of paging to find them. When the list holds MORE reviews than the count Google publishes, the summary says how many are still unpublished (`unpublished_estimate`): those cannot be replied to yet, and a reply attempt comes back as `review_not_replyable`, so do not retry them.
gbp_reviews
Shows which verification methods Google offers for a business listing (postcard to the address, phone call, SMS, email, or instant) and the current verification state. Starts nothing — read-only. An already-verified listing returns no options.
gbp_verification_options
Turns account-level CALL REPORTING on/off — the prerequisite for Google to track phone calls from ads as conversions. call_reporting: 'true'/'false' (show a Google forwarding number + report calls); call_conversion: 'true'/'false' (count qualifying calls as conversions). Provide at least one. To switch calls off send call_reporting='false' alone; call_conversion is not sent alongside it because Google rejects that pair and it has no effect while reporting is off. call_conversion_action_id: WHICH conversion action the calls are attributed to (id from list_conversion_actions); send 'default' to clear it back to Google's built-in action. Leave empty to keep the current one. A fresh account points at an internal placeholder that cannot be configured or reported on by name, so binding your own AD_CALL action is what makes call conversions readable. Pair with set_conversion_settings(phone_call_duration=…) to set the minimum call length. NOTE: Google forwarding numbers are only available in supported countries; enabling has no effect where unavailable. Called with NEITHER value it READS the current state instead of failing — use that before you switch anything on, and before you undo a change, because there is otherwise no way to know what the setting was. The same fields also appear under get_conversion_settings > account > call_reporting. confirm=false → dry-run.
set_call_reporting
Reads the extension assets LINKED to a campaign (sitelink / callout / structured snippet / call / promotion / price). If campaign_id is empty, returns extensions for all campaigns in the account. by_type: how many of each type are attached. READ-ONLY.
list_ad_extensions
Campaign-level settings (networks, location type, tracking template, EU political ads declaration, AI Max for Search), plus reading them: • geo_target_type: 'PRESENCE' (those PRESENT in the target location) | 'PRESENCE_OR_INTEREST' (also those interested). • search_partners: 'on' | 'off' — Search Partners. • display_expansion: 'on' | 'off' — Display expansion on a Search campaign. • tracking_url_template: campaign tracking template (e.g. '{lpurl}?utm_source=google'); send '-' to DELETE. • eu_political_ads: 'no' | 'yes' — the advertiser's declaration whether this campaign has European Union political ads. Google refuses targeting and other edits on a campaign until it is declared (MISSING_EU_POLITICAL_ADVERTISING_SELF_DECLARATION). Ask the user; do not answer for them. AI MAX FOR SEARCH (Search campaigns only). AI Max is Google's switch that lets a Search campaign reach beyond its keywords. With it ON: – search term matching: keywords behave like broad match and Google also matches searches from the landing pages and ads, so the campaign shows for searches you never added (check the search terms report — rows marked "AI Max"); – text customization: Google writes extra headlines/descriptions from your site and ads; – final URL expansion: Google may send a click to a different page of your site than the ad's final URL. It can bring new traffic, but it can also spend on unrelated searches (rentals, parking, hotels, other businesses' names); compare the "AI Max" rows' cost and conversions with your own keywords before deciding. • ai_max: 'on' | 'off' — the main switch. 'off' also turns text customization and final URL expansion off in the same change (Google requires that); keywords then match by their own match type again. • ai_max_text_customization: 'on' | 'off' — needs ai_max on. • ai_max_final_url_expansion: 'on' | 'off' — needs ai_max on AND text customization on. • ai_max_search_term_matching: 'on' | 'off' — applied to EVERY ad group of the campaign: 'off' keeps AI Max on for text/URL features but makes keywords match only by their own match type. Brand lists, locations of interest, URL inclusions and text guidelines are not set here. Any field left empty is NOT changed. confirm=false → if called with no fields provided, returns the campaign's CURRENT values, including the AI Max state and each ad group's search term matching (call with no parameters to READ).
manage_campaign_settings
Reads a campaign's CURRENT targeting: location (geo), radius/proximity targeting (radius + units + lat/lng), language, device, and audience (user_list) criteria + negative (excluded) ones — plus the campaign's geo_target_type (PRESENCE = people physically in the area, vs PRESENCE_OR_INTEREST). If campaign_id is empty, all campaigns. `ad_group_id` reads the AD GROUP's own criteria instead — location, language, audience and user list. This is the only way to see targeting on Demand Gen, where Google keeps geo, language and audience at ad group level, not on the campaign: for those campaigns the campaign-level read returns device criteria and nothing else, which made it impossible to verify what a Demand Gen campaign actually targets (measured on a live campaign that had 27 ad-group locations the campaign read could not see). Location values come back as geo IDs; pass one to geo_target_search to get its name. READ-only.
get_campaign_targeting
GOOGLE ADS ONLY — lists Google Ads account changes over the last N days IN DEPTH: who (user_email), from where (client_type), when, operation (CREATE/UPDATE/REMOVE), resource, CHANGED FIELDS, and old→new values. Max 30 days. Filter with resource_type (e.g. 'CAMPAIGN','AD_GROUP','AD_GROUP_CRITERION') and operation ('CREATE'|'UPDATE'|'REMOVE'). For the same audit trail on Meta (who changed which campaign/ad set/ad and when) use meta_change_history.
get_change_history
Renders how an existing ChatGPT Ads ad looks, plus the delivery blockers OpenAI reports for it. The preview shows appearance only — OpenAI is explicit that it does not prove the ad is eligible to serve — so this also requests the ad's serving issues and review status, which is what actually answers "why is this not running". Read-only.
chatgpt_ads_ad_preview
Shows ChatGPT Ads conversion tracking: pixels (data sources), conversion event settings with the campaigns they are attached to, and events received in the last ~15 minutes. Use it to answer "is my pixel firing" and "which campaigns measure which action". Recent events come from OpenAI's test stream (up to 50 events from roughly the last 15 minutes, per pixel; browser events show channel pixel_sdk, server events server_to_server) — an empty list only means nothing arrived in that window. If OpenAI has not enabled the stream for the account it answers 404 and this tool says so. Standard events can be the goal of a conversions-objective campaign; custom events can only be measured. Read-only.
chatgpt_ads_conversion_setup
ChatGPT Ads delivery report with every option OpenAI offers: hourly/daily/monthly buckets, platform/country/device breakdowns, zero-impression rows and conversion metrics. `scope_id` narrows to one campaign/ad group/ad (cmpn_/adgrp_/ad_); empty = whole account. `level`: account | campaign | ad_group | ad — one row per entity at that level. `granularity`: none (period total) | hourly (about 30 days of history) | daily | monthly; times are in the account time zone. `segment`: platform (android_app, android_web, desktop_web, ios_app, ios_web, web) | country | device | product — one at a time, not with hourly, not with conversions. `include_zero=true` adds campaigns/groups/ads that got no impressions (unsegmented only), which is how you see what is NOT delivering. `conversions=true` (granularity none or daily only) adds conversions, cpa, post_click_cvr, attributed sales and ROAS (null means not computable, not zero; conversions settle over about a day). Spend, CPC and CPM are in the account currency. Dates are YYYY-MM-DD (end inclusive); without dates the last `days` days. Rows are paged with `limit`/`offset`. Read-only.
chatgpt_ads_insights
Finds ChatGPT Ads location ids (countries, regions, markets, postal codes) to use in campaign location targeting. Returns id, name, type, country and region code. Pass the id (or a plain ISO country code such as TR) to update_chatgpt_ads_campaign include_locations / exclude_locations. Search in English or the local name ('Istanbul', 'England'); a country name can also match postal codes elsewhere, so check `country_code`. A valid location does not mean ads are allowed in that country — OpenAI's pilot country list and category policies still apply. Read-only.
chatgpt_ads_geo_lookup
Full details of one ChatGPT Ads campaign, ad group or ad by id, including everything that decides delivery. Campaign (cmpn_…): budget, schedule, objective, full location/platform/audience targeting, attached conversion events, serving issues. Ad group (adgrp_…): bid strategy and bid in the account currency, bid_too_low (with the 24-hour caveat: OpenAI does not raise it within 24 hours of an ad-group edit, so the time it becomes evaluable is returned), serving issues, its parent campaign and the context hints (paged by `hints_limit`/`hints_offset`). Ad (ad_…): the full creative — title, body, destination URL, image — plus review status, the review reason (for example a regulated health category) and serving issues with plain explanations. Read-only.
chatgpt_ads_details
Shows the ChatGPT Ads account-level spending limits: date-range windows and the recurring daily limit, with spend so far. An account limit caps spend across ALL campaigns; a campaign can have budget left and still stop because the account limit is used up. Amounts are in the account currency; end dates are exclusive (the limit ends at midnight of that day, account time zone). OpenAI only exposes these to an ad-account ADMIN key with billing permission — with an ordinary key the tool says exactly that instead of failing. Account limits exist only on postpaid (invoice) billing. Read-only.
chatgpt_ads_spend_limits
Checks what happened to a problem the user reported with report_issue: whether it is still open or resolved, when it was reported, and — once it is closed — what was actually done about it. Without this the only signal was the resolution e-mail, so the honest answer to "is that fixed yet?" was a guess. Pass `issue_id` for one report, or leave it out to list the user's own recent reports newest first. Only the user's own reports are visible. Read-only and free — checking never costs a credit.
issue_status
CLIENT REPORT DATA (Google Ads only) — returns the numbers of one Google Ads account, not a finished report; when the user asks for a report, marketing_report_pdf returns the designed report across every platform as a direct download link. This tool aggregates an account's period performance in a CLIENT-READY format: overall KPIs (cost/clicks/conversions/ROAS/CPA/CTR) + % change vs. the PREVIOUS period + top-spending campaigns. brand_name appears in the report title. For a shareable page, use client_report_link. READ-ONLY.
client_report
Competitor AD intelligence — fetches a brand's/domain's LIVE ads from public ad libraries. platform: google (Ads Transparency Center) | meta (Meta Ad Library; requires a connected Meta account) | linkedin. Returns only publicly available ad creatives/copy; competitors' ORGANIC keywords are NOT available in Google's APIs.
competitor_ads
Generates an authorization link to connect Google Business Profile (My Business) — editing business info/hours/website, publishing posts, and replying to reviews. Stored with a separate encrypted token; does not touch the Google Ads connection.
connect_business_profile
Generates a one-time authorization link to connect a Google Ads account. Once the user clicks the link and approves with Google, the refresh token is stored encrypted.
connect_google_ads
Opus Growth ChatGPT Plugin FAQ
How the directory, categories and Discoverability Score work.
Read the methodologyHow do I improve Opus Growth's ChatGPT Plugin discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are Opus Growth alternatives on ChatGPT?
As of 2026-11-03, Opus Growth competes with Ad Account Health Check, Ad Reporting by PaidSync.ai, Ad Superpowers, Adalysis, AdBeacon, AdKit - Ads Manager, Adlane, AdLiftr and 72 more in ChatGPT Ad Campaign Analytics & Reporting, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.


