HireOtto Performance Ads
Manage advertising campaigns
- Category
- Marketing
- Primary Subcategory
- Ad Campaign Analytics & Reporting
Integration details
Description
HireOtto Performance Ads connects to your Google Ads accounts through user-authorized OAuth and the official Google Ads API. Review performance, research keywords, audit accounts, and create or update campaigns, ads, budgets, bidding, and conversion settings. It also retrieves organic search reports from connected Search Console properties. Some actions consume HireOtto credits or create temporarily stored CSV exports that are periodically deleted. HireOtto is an independent service and is not affiliated with or endorsed by Google.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Ad Campaign Analytics & Reporting
- Secondary Subcategories
- None listed
- Brand
- HireOtto
- Access
- Account required
- First tracked
- 2026-09-26
- Tool count
- 34
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Get alerts for HireOtto Performance Ads
Get updates when HireOtto Performance Ads’s Discoverability Score or category rank changes.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Ad Campaign Analytics & Reporting
View Category34 tools agents can invoke
Start Google Ads authentication and return a link the user must open. What this tool does ------------------- • Creates an authorization URL for the user to grant access to Google Ads. • This is the FIRST step before any Google Ads action (reports, create/update entities). • Starts a user-authorized OAuth connection workflow; consent is completed in the browser. • Supports connecting to multiple Google logins that have access to Google Ads. When to call ------------ • If you see errors like “Google Ads isn’t connected.” • If the user says things like: "connect/link/login Google Ads", "authenticate Google Ads", "let’s connect to Google Ads", "authorize my Google Ads" • If no customer accounts are available or selected and the workspace isn’t connected yet. • If the user wants to connect an additional Gmail: call this tool again with profile_id (a nickname) and complete OAuth with that email. profile_id (optional) --------------------- • Omit to connect your default Google login (the first one you connected). • Only add a profile id when the user is looking to add another gmail account. • Set to a nickname to add another Google login, e.g.: - "agency_mcc" - "client_ops" - "gmail2" • Avoid using ":" in profile_id (":" is used internally in the OAuth state value). What to do with the result (client behavior) -------------------------------------------- • Show the returned URL to the user and ask them to open it and complete consent. Returns ------- dict with "authorization_url": str (the link to open) Example client flow ------------------- 1) Call authenticate_google_ads() 2) Display authorization_url. Example (connect another Gmail) ------------------------------- 1) Call authenticate_google_ads(profile_id="agency_mcc") 2) Display authorization_url and complete consent with that Gmail. Side effects and data handling: Completing consent stores connection tokens and account information in HireOtto. Reconnecting an existing profile can replace its saved connection.
authenticate_google_ads
Start Google Search Console authentication and return a link the user must open. Use this when: - Search Console is not connected. - The user asks to connect Search Console. - The user wants SEO/search performance, organic queries, page performance, indexing, or sitemap data. - The user needs to connect another Google login that has Search Console access. profile_id: - Optional. Omit for the default Google login. - Use only when connecting another Google login, e.g. "client_search_console" or "second_gmail". - Avoid ":" in profile_id. After the user opens the returned URL and completes consent, HireOtto saves the Search Console tokens and accessible sites automatically.
authenticate_search_console
Unified *create* endpoint for common App-campaign entities. customer_id is required for all supported actions below. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) Supported actions: - `create_app_ad_group`: Creates an ad group under an existing App campaign. Args: • customer_id (required) • campaign_id (required) • ad_group_name (required) • target_cpa (optional) - only relevant for some engagement campaign paths • user_list_ids (optional / required depending on subtype) - APP_CAMPAIGN: not supported - APP_CAMPAIGN_FOR_ENGAGEMENT: typically required - APP_CAMPAIGN_FOR_PRE_REGISTRATION: not supported - Preferred: ["123456789", "987654321"] - Also accepted: full resource names - Also accepted: same JSON list as a string Tip: Use `list_user_lists_for_app_engagement` first to find audience lists that look suitable for engagement campaigns. - `create_app_ad`: Creates an app ad under an existing App ad group. Args: • customer_id (required) • ad_group_id (required) • headlines (required) - list or JSON string list - must have at least 1 and at most 5 headlines - each headline must be <= 30 characters • descriptions (required) - list or JSON string list - must have at least 1 and at most 5 descriptions - each description must be <= 90 characters • image_asset_resource_names (optional) - list of existing image asset resource names • youtube_video_asset_resource_names (optional) - list of existing video asset resource names • html5_media_bundle_asset_resource_names (optional) - list of existing media bundle asset resource names • app_url (optional / required depending on subtype) - APP_CAMPAIGN: optional - APP_CAMPAIGN_FOR_ENGAGEMENT: required - APP_CAMPAIGN_FOR_PRE_REGISTRATION: optional - This should be a valid final app URL / app deep link, not a standard web landing page URL • status (optional) - "ENABLED" or "PAUSED" - default: "ENABLED" Notes: - Non-text assets must already exist and be passed as resource names. - If action fails because a user list is not eligible for engagement targeting, try another user list. - If action fails for an engagement ad due to app_url validation, the provided app_url may not be a valid final app URL / deep link for the app. Returns ------- On success -> `{"success": True, "action": "<action>", "data": ...}` On error -> `{"error": "...", "action": "<action>"}` Side effects and data handling: Execution records HireOtto usage and can consume 2 credits.
create_app_ad_entities
Creates a paused Google App campaign with a dedicated unshared budget. Also applies optional campaign-level location and language targeting. customer_id is required. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) Required arguments: customer_id, campaign_name, amount, app_id, app_store, goal Args: - customer_id (required): The Google Ads customer ID. - campaign_name (required): Name of the campaign to create. - amount (required): Daily budget amount. No currency required as it is set at account level. - app_id (required): App identifier. Example values: • Android: "com.example.app" • iOS: "123456789" - app_store (required): The app store for the app. Accepted values: • "GOOGLE_APP_STORE" • "APPLE_APP_STORE" Also accepted: • "google_play" • "apple" • "ios" - goal (required): App campaign goal / setup path. Accepted values: • "installs" • "in_app_actions" • "in_app_action_value" • "engagement_in_app_actions" • "engagement_in_app_action_value" • "pre_registration" - locations (optional): List of locations to target. Example values: ["United States", "India"] - language (optional): Language to target. Default: "en" - start_date (optional): Start date in YYYYMMDD format. If omitted, defaults to tomorrow. - end_date (optional): End date in YYYYMMDD format. - target_cpa (optional): Used for app goals that support or require target CPA. - target_roas (optional): Used for app goals that support or require target ROAS. - conversion_action_ids (optional / required depending on goal): • May be required for action-focused and value-focused app goals. • Can be passed as a list of bare IDs or full resource names. • Preferred: ["123456789", "987654321"] Also accepted: ["customers/123/conversionActions/123456789"] Also accepted as the same JSON list as a string. - contains_eu_political_advertising (optional): Explicit EU political advertising declaration. Accepted values: • "DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING" • "CONTAINS_EU_POLITICAL_ADVERTISING" Goal behavior summary: - "installs" • Creates an APP_CAMPAIGN • target_cpa may be optional depending on available app bidding mode - "in_app_actions" • Creates an APP_CAMPAIGN • typically requires conversion_action_ids - "in_app_action_value" • Creates an APP_CAMPAIGN • typically requires conversion_action_ids • uses target_roas path when provided - "engagement_in_app_actions" • Creates an APP_CAMPAIGN_FOR_ENGAGEMENT • typically requires conversion_action_ids - "engagement_in_app_action_value" • Creates an APP_CAMPAIGN_FOR_ENGAGEMENT • typically requires conversion_action_ids • uses target_roas path - "pre_registration" • Creates an APP_CAMPAIGN_FOR_PRE_REGISTRATION Returns: dict: campaign id, budget id, campaign subtype, bidding goal type and applied targeting criteria count. Side effects and data handling: Execution records HireOtto usage and can consume 5 credits.
create_app_campaign
Create Demand Gen ad groups, reusable assets, or ads. This is the main creation tool for Demand Gen entities after the campaign shell already exists. Supported actions: 1. action="create_ad_group" Creates a Demand Gen ad group under an existing Demand Gen campaign. Required: customer_id, campaign_id, ad_group_name Accepted values / important args: - status: - "PAUSED" - "ENABLED" - channel_strategy: - "ALL_CHANNELS" Includes all supported Demand Gen channels. - "ALL_OWNED_AND_OPERATED_CHANNELS" Google-owned channels, including Maps and excluding Display. - selected_channels: Dict/JSON object for explicit inventory selection. Keys accepted by the action: - "youtube_in_stream" - "youtube_in_feed" - "youtube_shorts" - "discover" - "gmail" - "display" - "maps" Aliases accepted: - "shorts" -> "youtube_shorts" - "in_stream", "youtube in-stream", "youtube instream" -> "youtube_in_stream" - "in_feed", "youtube feed" -> "youtube_in_feed" At least one selected channel must be true. - locations: Optional list of human-readable location names, e.g. ["India", "Mumbai"]. Do not pass location IDs here. - negative_locations: Optional list of human-readable location names to exclude. - language: Optional language name/code. Defaults to "english". Accepted by the action: - "english" / "en" - "spanish" / "es" - "french" / "fr" - "german" / "de" - "italian" / "it" - "portuguese" / "pt" - "japanese" / "ja" - "korean" / "ko" - "hindi" / "hi" - "chinese" / "zh" Pass None to leave language targeting unset. - audience_resource_names: Optional list of full Google Ads audience resource names. Demand Gen currently expects one audience for this action. Use this when: - The user wants a new Demand Gen ad group. - The user specifies channel controls, audience, language, or location targeting at the ad group level. Use channel_strategy for broad Google Ads inventory presets. Use selected_channels when the user explicitly names channels like YouTube Shorts, Gmail, Discover, or Display. Do not pass both unless the user deliberately wants selected_channels to override strategy. 2. action="create_asset": Creates a standalone reusable asset for Demand Gen ads. Required: customer_id, asset_type, asset_name Accepted asset_type values: - "TEXT" Requires text. - "LOGO_IMAGE" Requires image_url. - "MARKETING_IMAGE" Requires image_url. - "SQUARE_MARKETING_IMAGE" Requires image_url. - "YOUTUBE_VIDEO" Requires youtube_video_id. - "CALL_TO_ACTION" or "CTA" Requires text containing a supported CTA value. Supported CTA text values: - Use human-readable CTA text, for example: "Apply now" "Book now" "Contact us" "Download" "Learn more" "Visit site" "Shop now" "Sign up" "Get quote" "Subscribe" "See more" "Donate now" Use this when: - The same creative asset may be reused across multiple Demand Gen ads. - The user explicitly asks to upload/create assets before creating ads. 3. action="create_ad": Creates a Demand Gen ad inside an existing Demand Gen ad group. Required: customer_id, ad_group_id, ad_name, ad_type, final_urls Accepted ad_type values: - "SINGLE_IMAGE" or "MULTI_ASSET" - "CAROUSEL_IMAGE" or "CAROUSEL" - "VIDEO" or "VIDEO_RESPONSIVE" Accepted status values: - "PAUSED" - "ENABLED" CTA behavior: - For SINGLE_IMAGE / MULTI_ASSET ads, call_to_action_text is passed directly to Google Ads as display text. - Use human-readable CTA text, for example: "Apply now" "Book now" "Contact us" "Download" "Learn more" "Visit site" "Shop now" "Sign up" "Get quote" "Subscribe" "See more" "Donate now" - Do not use enum-style CTA values like "LEARN_MORE" for SINGLE_IMAGE / MULTI_ASSET ads; Google may reject them as invalid call to action text. - For VIDEO / VIDEO_RESPONSIVE ads, the action creates a CALL_TO_ACTION asset internally - prefer human-readable CTA input. Text / business inputs: - business_name - call_to_action_text - headlines - descriptions - long_headlines Existing asset inputs: - logo_image_asset_resource_names - marketing_image_asset_resource_names - square_marketing_image_asset_resource_names - portrait_marketing_image_asset_resource_names - tall_portrait_marketing_image_asset_resource_names - classic_display_image_asset_resource_names - video_asset_resource_names - carousel_card_asset_resource_names Inline asset convenience: - logo_image_urls - marketing_image_urls - square_marketing_image_urls - youtube_video_ids Carousel-specific: - carousel_cards can be a list of dicts or JSON string list. - Use carousel_cards when card assets should be created during ad creation. - Use carousel_card_asset_resource_names when card assets already exist. - breadcrumb1 and breadcrumb2 are optional carousel breadcrumb fields. Asset automation controls: - generate_animated_images: Applies only to SINGLE_IMAGE / MULTI_ASSET ads. Defaults to False, which explicitly opts out. - generate_landing_page_text: Applies only to VIDEO / VIDEO_RESPONSIVE ads. Defaults to False, which explicitly opts out. - Pass True only when the user explicitly wants the applicable automation. - These controls are not supported for carousel ads. Important behavior: - Lists/dicts can be passed as native values or JSON strings. - Prefer status=PAUSED unless the user explicitly asks to enable. - For simple one-off ad creation, inline image/video inputs are often easier. - For reusable creative libraries, create assets first, then pass asset resource names. - For carousel ads, do not pass only raw image assets unless the action expects them; carousel cards usually need card-level structure. Side effects and data handling: Execution records HireOtto usage and can consume 3 credits for ad-group creation, 2 for reusable asset creation, or 5 for ad creation.
create_demand_gen_ads_entities
Create a Demand Gen campaign shell without ad groups, assets, or ads. Required: - customer_id - campaign_name - either budget_id or budget_amount Budget behavior: - If budget_id is provided, it must refer to an existing non-shared budget. - If budget_id is omitted, budget_amount is required and a new non-shared budget is created. - Demand Gen campaigns cannot use shared budgets. Campaign goal / bidding: - campaign_goal accepted values: - "CONVERSIONS" - "CLICKS" - "CONVERSION_VALUE" - "YOUTUBE_ENGAGEMENTS" - target_cpa, target_roas, and target_cpc are optional goal-specific targets. - If no target is provided, the action chooses the closest valid Google Ads bidding strategy for the selected Demand Gen goal. Accepted values: - budget_period: - "DAILY" - "CUSTOM_PERIOD" - status: - "PAUSED" - "ENABLED" Prefer PAUSED unless the user explicitly asks to launch enabled. - contains_eu_political_advertising: - "DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING" - "CONTAINS_EU_POLITICAL_ADVERTISING" - positive_geo_target_type: - "PRESENCE" - "PRESENCE_OR_INTEREST" - negative_geo_target_type: - "PRESENCE" - included_devices: - "DESKTOP" - "MOBILE" - "TABLET" - "CONNECTED_TV" Also accepted by the action: COMPUTER/COMPUTERS, MOBILE_PHONE/MOBILE_PHONES, PHONE/PHONES, TABLETS, TV/TV_SCREEN/TV_SCREENS/CONNECTED_TVS. Omit included_devices to keep all devices eligible. - ad_schedules: List of dicts or JSON string list. Each item may include: - day_of_week: "MONDAY"..."SUNDAY" - start_hour: 0-23 - end_hour: 0-23 - start_minute: "ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE" - end_minute: "ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE" Optional settings: - status: defaults to PAUSED. Prefer PAUSED unless the user explicitly asks to launch enabled. - start_date / end_date: pass YYYYMMDD or full datetime strings. - contains_eu_political_advertising: defaults to DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING. - positive_geo_target_type / negative_geo_target_type: default to PRESENCE. - tracking_url_template and final_url_suffix are optional tracking settings. - included_devices accepts DESKTOP, MOBILE, TABLET, CONNECTED_TV. Omit included_devices to keep all devices eligible. - ad_schedules can be a list of schedule dicts or a JSON string list. After this: - Use create_demand_gen_ads_entities(action="create_ad_group") to add an ad group. - Then use create_demand_gen_ads_entities(action="create_asset") or create_demand_gen_ads_entities(action="create_ad") to add creatives. Side effects and data handling: Execution records HireOtto usage and can consume 10 credits.
create_demand_gen_campaign
Creates a paused Google Search campaign with a dedicated unshared budget. The start date defaults to today in the Google Ads account timezone and can be overridden with start_date. Sets location and language targeting, bidding strategy, and applies a UTM-based tracking template. Defaults: STANDARD delivery method, PRESENCE-based geo targeting, Google Search only. Returns campaign and budget IDs with number of targeting criteria applied. Args: - customer_id (required): The Google Ads customer ID. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) - campaign_name (required): Name of the campaign to create. - amount (required): Daily budget amount. No currency required as it is set an account level. - locations (required): List of locations to target. Example_values: ["United States", "Canada", "India"] - bidding_strategy: Bidding strategy type (default: "TargetSpend"). Accepted values: - "ManualCpc" - "MaximizeConversions" → supports: target_cpa (float, optional) - "MaximizeConversionValue" → supports: target_roas (float, optional) - "TargetImpressionShare" → requires: • impression_location (Placement preference on the search results page): string, allowed_values: ABSOLUTE_TOP_OF_PAGE | TOP_OF_PAGE | ANYWHERE_ON_PAGE) • location_fraction (Desired impression share as a fraction (e.g., 0.5 for 50%)): float • cpc_bid_ceiling: float - "TargetSpend" → supports: • cpc_bid_ceiling (float, optional) • TARGET_SPEND - called 'Maximise Clicks' in Google Ads UI - language: Language to target (default: "en" for English). - start_date: Optional campaign start date in YYYY-MM-DD format. Defaults to today in the Google Ads account timezone. - dynamic_search_ads_setting: Optional object that enables DSA on this Search campaign. Requires domain_name and language_code together. Example: {"domain_name":"example.com","language_code":"en","use_supplied_urls_only":false} Omit it for a normal Search campaign. `use_supplied_urls_only=true` is intended for campaigns with a DSA page feed attached. Returns: dict: budget id, campaign id and applied targeting criteria count. Side effects and data handling: Execution records HireOtto usage and can consume 5 credits.
create_search_campaign
Unified *create* endpoint for common Search-Ads objects customer_id is required for all supported actions below. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) Action and Required Arguments mapping: `create_adgroup`: customer_id, campaign_id, adgroup_name, cpc_bid (optional) cpc_bid is the ad-group default CPC bid in the account currency. It is only supported for Search campaigns using MANUAL_CPC. `create_responsive_search_ad`: customer_id (str): The customer ID. adgroup_id (str): The ad group ID. headlines (dict or list): Headlines to be used in the ad. • If a dict is provided, keys are headline texts and values are pin fields (e.g., "HEADLINE_1"). • If a list is provided, no pinning is applied. Must have at least 3 and at most 15 headlines. Each headline must be ≤ 30 characters. descriptions (dict or list): Descriptions for the ad. • If a dict is provided, keys are description texts and values are pin fields (e.g., "DESCRIPTION_1"). • If a list is provided, no pinning is applied. Must have at least 2 and at most 4 descriptions. Each description must be ≤ 90 characters. final_url (str): The final URL for the ad. path1 (str, optional): Optional first path for the display URL. Must be ≤ 15 characters if provided. Can be omitted or empty. path2 (str, optional): Optional second path for the display URL. Must be ≤ 15 characters if provided. Can be omitted or empty. `create_dynamic_adgroup`: customer_id, campaign_id, adgroup_name. Creates a SEARCH_DYNAMIC_ADS ad group. Optional: status (PAUSED by default), cpc_bid for MANUAL_CPC campaigns, and URL tracking fields. `create_dynamic_search_ad`: customer_id, adgroup_id, description. Optional: description2, status (PAUSED by default), and URL tracking fields. Do not supply headlines, paths, or final_url; Google generates them. DSA-level URL tracking fields can be provided during creation but cannot be updated afterward. Prefer ad-group tracking when the tracking configuration may need to change later. `create_dynamic_target`: customer_id, adgroup_id, criterion_name. conditions is an array of 0-3 {"operand":"URL","argument":"/services/"} objects. Operands: URL, CATEGORY, PAGE_TITLE, PAGE_CONTENT, CUSTOM_LABEL. CUSTOM_LABEL arguments must match labels on a DSA page feed linked to the campaign. Conditions are ANDed; [] or omission targets all pages. Optional: negative, status, eligible cpc_bid, and URL tracking fields. Positive targets default to PAUSED; negative targets are exclusions and default to ENABLED. `create_negative_keyword_list`: customer_id (str): The customer ID. list_name (str): The name for the new negative keyword list. keywords (str|array|object, optional): Initial keywords to add. • If array: ["employment", "jobs", ...] –> all will use `match_type`. • If object: {"employment": "BROAD", "jobs": "PHRASE", ...} • *Preferred* → array or object. *Also accepted* → the same JSON **as a string**; it will be decoded. match_type (str, optional): A single match type for all keywords if keywords is provided as a list. Example values include "BROAD", "PHRASE", or "EXACT". `add_keywords_to_adgroup`: (Add POSITIVE/TARGETED keywords to an ad group. Note: In Google Ads, positive keywords can ONLY be added at the ad group level, never at the campaign level.) customer_id campaign_id adgroup_id keywords (str|array|object, optional): keywords to add. • If array: ["employment", "jobs", ...] –> all will use `match_type`. • If object: {"employment": "BROAD", "jobs": "PHRASE", ...} • *Preferred* → array or object. *Also accepted* → the same JSON **as a string**; it will be decoded. match_type (str, optional): A single match type for all keywords if keywords is provided as a list. Example values include "BROAD", "PHRASE", or "EXACT". negative (bool, optional): Set this as True to add keywords as negative keywords cpc_bid (optional): One CPC bid in the account currency to apply to all positive keywords created in this call. CPC bids cannot be assigned to negative keywords and are only supported when the campaign uses MANUAL_CPC. If an action fails because the EU political advertising status is undeclared, ask the user for the actual declaration before calling `update_search_campaign` with action `update_eu_political_advertising_declaration` for the affected campaign(s), then retry. Returns ------- On success → `{"success": True, "action": "<action>", "data": ...}` On error → `{"error": "...", "action": "<action>"}` Side effects and data handling: Execution records HireOtto usage and can consume 2 credits.
create_search_ads_entities
Create Performance Max campaigns or asset groups.
create_pmax_campaign
Review campaign delivery and budget pacing for operational exceptions. Use this Google Ads analysis for a daily or short-period account check. It lists the current campaign inventory, pulls campaign performance for the selected period and a preceding baseline, checks campaign serving diagnostics, and aggregates campaigns that share a budget before evaluating pacing. It then returns prioritized findings with evidence and suggested follow-up actions. This audit focuses on delivery interruptions, spend spikes or drops, and over- or underspending against daily budgets. It intentionally does not review search terms, keywords, ads, locations, or devices; use weekly_optimization_audit for optimization analysis.
daily_ops_audit
View the current HireOtto billing status for the workspace/team wallet. Returns the current plan, trial/period dates, credits used/remaining, entitlement flags, and an informational plans URL. Side effects and data handling: Retrieves billing information without consuming credits or persisting a usage record.
get_billing_status
Retrieve Google Ads account change history. Use this tool when the user wants to know: - what changed in the account - when it changed - who changed it - whether account edits happened during a reporting window Actions ------- - 'get_change_status' Broad overview of changed resources. Use for quick scans like: - "Did anything change recently?" - "Which campaigns/ad groups were touched?" - 'get_change_events' Detailed change timeline with who/when/what changed. Use when the user asks: - what exactly changed - when it changed - who changed it - whether edits may have affected performance in a given period How to choose ------------- - Use 'get_change_status' for a quick overview. - Use 'get_change_events' when precision matters or when correlating changes with performance. customer_id ----------- Google Ads customer ID (without hyphens) date_range ---------- Required for both actions. Accepted formats: - Predefined string: "TODAY", "YESTERDAY", "LAST_7_DAYS", "LAST_14_DAYS", "LAST_30_DAYS" - Custom dict: {"start_date": "2026-04-01", "end_date": "2026-04-14"} Notes: - These actions do not use segments.date. - get_change_status filters on change_status.last_change_date_time. - get_change_events filters on change_event.change_date_time. - get_change_events must query within the past 30 days and requires LIMIT. - For change_event, prefer predefined ranges unless the user really needs a custom window. - Very recent changes may take a few minutes to appear. campaign_id ----------- Optional campaign filter for both actions. adgroup_id ---------- Optional ad group filter for get_change_status only. output_mode ----------- - "summary": inline rows only - "summary_and_csv": inline rows + CSV URL - "csv_only": CSV URL only Prefer CSV when: - the user wants full history - the result may be large - detailed change_event output would consume too much context limit ----- Max inline rows (default: 100). For get_change_events, the effective API query always requires LIMIT and is capped at 10000 rows. sort_order ---------- "desc" (default) or "asc" Returns ------- Success → {"success": True, "action": "<action>", "data": ..., "export": {...optional...}} Error → {"error": "...", "action": "<action>"} Side effects and data handling: Detailed change events include the actor email, changed fields, and old/new resource snapshots. Request detailed events only when needed for the user inquiry. Execution records HireOtto usage and can consume 5 credits. CSV exports are temporarily stored in private storage and periodically deleted. Signed download links expire after the requested TTL; link expiry does not determine the file deletion time.
get_change_history
Retrieve performance metrics and reports for Google Ads entities.
get_performance_report
Query Google Search Console performance data. Use this for organic Google Search analysis: - Top organic queries - Top organic landing pages - Page performance by country/device - Query rankings in a specific country - US vs Europe page/query performance - Branded vs non-branded organic search - SEO + Google Ads keyword discovery - Organic pages with strong impressions but weak CTR - Organic queries where paid search campaigns may be useful Required: - site_url: Search Console property URL. Use search_console_resources(action="list_sites") if unknown. Examples: - "sc-domain:example.com" - "https://www.example.com/" - start_date, end_date: YYYY-MM-DD format. Dates are interpreted by Search Console in Pacific Time. For stable reporting, prefer ending at yesterday or earlier. Use recent data only when the user explicitly asks for fresh/incomplete data. dimensions: - Optional list. Default: ["query"]. - Common values: - "query": organic search queries - "page": landing pages / URLs - "country": 3-letter country code in results - "device": DESKTOP, MOBILE, TABLET - "date": daily trend - "hour": hourly trend; use with data_state="hourly_all" - "searchAppearance": result feature type. Values vary by property; discover by querying this dimension. search_type: - "web" default. Google Search All tab. - "image": Image Search - "video": Video Search - "news": News tab in Google Search - "discover": Google Discover - "googleNews": news.google.com and Google News app dimension_filter_groups: - Optional filters. Use this for real segmentation. - Can be a JSON string, dict, or list. - Shape: [ { "groupType": "and", "filters": [ {"dimension": "country", "operator": "equals", "expression": "USA"}, {"dimension": "device", "operator": "equals", "expression": "DESKTOP"} ] } ] Filter dimensions: - "country": use 3-letter ISO codes such as USA, IND, GBR, FRA, DEU. - "device": DESKTOP, MOBILE, TABLET. - "page": URL or URL substring depending on operator. - "query": search query text. - "searchAppearance": feature value. Discover available values with dimensions=["searchAppearance"]. Filter operators: - "equals": exact match. Case-sensitive for page/query. - "contains": substring match. Non-case-sensitive. - "notEquals" - "notContains" - "includingRegex": RE2 regex include. - "excludingRegex": RE2 regex exclude. groupType: - Only "and" is currently supported by Search Console. aggregation_type: - Optional. Usually leave unset or use "auto". - "auto": let Search Console decide. - "byPage": aggregate by canonical URI. - "byProperty": aggregate by property. - Important: If grouping or filtering by page, do NOT use byProperty. - byProperty is not supported for discover or googleNews. - "byNewsShowcasePanel" is only for News Showcase with specific searchAppearance filters. data_state: - Optional. - "final": finalized data only. Default if omitted. - "all": include fresh/incomplete daily data. - "hourly_all": include hourly data; use with dimensions=["hour"]. output_mode: - "summary": Return inline rows only, limited by `limit`. - "summary_and_csv": Return inline rows plus signed CSV export. Recommended default. - "csv_only": Return CSV export plus metadata, minimal inline data. limit: - Inline row count. Default 50. - Use this for the visible/top rows in chat. export_limit: - Max rows fetched/exported. Default 25000, which is Search Console's per-request max. - Use lower values for quick checks; use 25000 when the user asks for full data/export. Good examples: - Page performance in the US: dimensions=["page"], dimension_filter_groups=[{"groupType":"and","filters":[{"dimension":"country","operator":"equals","expression":"USA"}]}] - Query rankings in the US: dimensions=["query"], dimension_filter_groups=[{"groupType":"and","filters":[{"dimension":"country","operator":"equals","expression":"USA"}]}] - Page performance by country/device: dimensions=["page","country","device"] - US desktop queries containing a term: dimensions=["query"], filters on country=USA, device=DESKTOP, query contains <term> - Discover available search appearances: dimensions=["searchAppearance"] Notes: - Results are generally sorted by clicks descending, except date grouping is chronological. - Search Console does not guarantee all possible rows; it returns top rows within API limits. - FAQ rich result support is being deprecated in the Search Console API, so don't hard-code FAQ as a recommended searchAppearance. Side effects and data handling: Execution records HireOtto usage and can consume 5 credits. CSV exports are temporarily stored in private storage and periodically deleted. Signed download links expire after the requested TTL; link expiry does not determine the file deletion time.
get_search_console_performance
Perform a broad monthly or quarterly Google Ads account-health review. Use this Google Ads analysis for a lower-frequency structural and configuration assessment rather than daily monitoring. It combines account and campaign settings, current and comparison-period performance, enabled-keyword data, negative-keyword coverage, geographic and device performance, and Search visibility. It then aggregates the raw rows into account-level distributions and prioritized findings with evidence and CSV exports. Checks include auto-tagging, Search/Display network settings, location mode, language targeting, keyword count by ad group, match-type performance, Quality Score and its components, negative-keyword presence, and impression share lost to budget or rank. Optional RSA review checks headline and description counts and pinning. This audit does not use CRM, competitor, landing-page experiment, or other external data.
account_health_audit
Keyword planning tool (Keyword Planner-style) for: 1) Keyword IDEAS (expansion) and 2) Historical METRICS (scoring a known keyword or keyword list) When to use ----------- Use this tool when the user asks for keyword research, keyword ideas, keyword expansion, or keyword metrics (search volume, competition, bid ranges) for specific keywords. - User wants NEW keyword suggestions/ideas → use "generate_keyword_ideas" - User wants metrics for SPECIFIC/KNOWN keywords they already have → use "generate_keyword_historical_metrics" - User says "keyword ideas for X" or "expand X" or "suggest keywords" → use "generate_keyword_ideas" - User says "metrics for X" or "volume for X" or "what's the search volume for X" → use "generate_keyword_historical_metrics" Quick Decision Tree ------------------- Does user have specific keywords they want metrics for? → YES: generate_keyword_historical_metrics → NO (want suggestions): generate_keyword_ideas Supported actions ----------------- - "generate_keyword_ideas" Generates new keyword ideas from seeds (keyword_texts, page_url, or both). Returns: Expanded keyword list WITH metrics for each Required inputs: - At least one of: keyword_texts OR page_url - "generate_keyword_historical_metrics" Returns historical metrics for specific keywords (no expansion). Required inputs: - keywords (list of keywords) Args: - action (required): Must be one of: - "generate_keyword_ideas" - "generate_keyword_historical_metrics" - customer_id (required): The Google Ads customer ID. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) - keyword_texts (optional): Seed keywords for ideas. Example: ["plumber near me", "drain cleaning"] Used only for action="generate_keyword_ideas". - page_url (optional): URL seed for ideas. Example: "https://example.com/service-page" Used only for action="generate_keyword_ideas". - keywords (optional): Keywords to score (metrics) with no expansion. Example: ["crm software", "b2b crm", "sales engagement"] Required for action="generate_keyword_historical_metrics". - locations (optional): Location targeting. Accepts list of location names and/or geo IDs. Example_values: ["United States", "United Kingdom", "India"] or [2840, 2826] Default: ["United States"] - location_mode: How to apply multiple locations (default: "combined") - "combined": one request across all locations (aggregated) - "per_location": separate results for each location (recommended when the user says "US/UK/IN") - language: Language (default: "english"). Example_values: "english", "en", "hindi", "hi" - keyword_plan_network: Network (default: "GOOGLE_SEARCH"). Example_values: - "GOOGLE_SEARCH" - "GOOGLE_SEARCH_AND_PARTNERS" - include_adult_keywords: Include adult keywords (default: false) - historical_months: Default 12 complete months (default: 12). Ignored if historical_start provided. - historical_start / historical_end: "YYYY-MM" range. If omitted, defaults to last complete month going back `historical_months`. - include_monthly_searches: Include monthly time-series in output (default: false). Can increase payload size. - include_average_cpc: Include legacy avg CPC (default: true). Note: legacy/spotty—can be 0 or missing in some accounts. - limit: Max rows returned (default: 25). In per_location mode, limit applies PER location. For action="generate_keyword_historical_metrics", results are only for the provided keywords. The tool will still sort + apply limit. To avoid dropping keywords, set limit >= number of keywords. If you pass more keywords than the default limit, increase limit accordingly. - sort_by: default "avg_monthly_searches". Allowed: avg_monthly_searches | competition_index | low_top_of_page_bid | high_top_of_page_bid | average_cpc - sort_order: "desc" (default) or "asc" - min_avg_monthly_searches: Optional filter. - competition: Optional filter list. Example_values: ["LOW","MEDIUM","HIGH"] - output_mode (default: "summary"): - "summary": return inline results only (best for chat UX). - "summary_and_csv": return inline summary + a signed CSV download URL (best for automation / large outputs). - "csv_only": return only the CSV export + export metadata (minimal inline). - export_ttl_minutes (default: 30): How long the CSV signed URL should remain valid. - export_limit (default: 5000): Max rows to export to CSV when output_mode includes CSV. Export object (when output_mode includes CSV): export.download_url: Signed URL to download the CSV (expires after export_ttl_minutes). Returns ------- Success → {"success": True, "action": "<action>", "data": ..., "export": {...optional...}} Error → {"error": "...", "action": "<action>"} Quick examples -------------- Ideas: { "action": "generate_keyword_ideas", "customer_id": "1234567890", "keyword_texts": ["plumber near me"], "locations": ["United States"], "limit": 50, "sort_by": "avg_monthly_searches" } Historical metrics: { "action": "generate_keyword_historical_metrics", "customer_id": "1234567890", "keywords": ["b2b crm", "crm software"], "locations": ["United States", "United Kingdom", "India"], "location_mode": "per_location", "limit": 50 } Side effects and data handling: An optional page_url is sent to the Google Ads API as a public URL seed for keyword ideas. Execution records HireOtto usage and can consume 10 credits. CSV exports are temporarily stored in private storage and periodically deleted. Signed download links expire after the requested TTL; link expiry does not determine the file deletion time.
keyword_planner
Lists all Google ads accounts accessible to the authenticated user.
list_accessible_accounts
List Google Ads entities for discovery and navigation.
list_search_ads_entities
Save a quick feedback/testimonial/review note for the builder. Side effects and data handling: Stores the submitted feedback for HireOtto and records usage and a zero-credit billing event; it does not publish the note as a testimonial.
log_feedback
Create and manage asset-based Dynamic Search Ads page feeds. All Google Ads mutations are validated before execution. Page-feed Asset fields (page_url and labels) are immutable, so edits use replacement assets and atomically unlink the old feed memberships. Removed/replaced Asset resources remain in the account because Google Ads does not allow deleting them. Each page_url must be unique within a feed; changing labels does not allow the same URL to be linked twice. Actions: `create_feed`: customer_id, feed_name, pages; campaign_id is optional. pages is an array of 1-100 objects: [{"page_url":"https://example.com/service","labels":["Services"]}] Creates the PAGE_FEED AssetSet, page Assets, membership links, and optional campaign link in one atomic request. `add_pages`: customer_id, asset_set_id, pages. Adds 1-100 new immutable page assets to an existing feed. `replace_pages`: customer_id, asset_set_id, replacements. Each replacement has asset_id, page_url, and optional labels. Use this to change a URL or its labels. Old feed links are removed and the replacements are created and linked in one atomic request. `remove_pages`: customer_id, asset_set_id, asset_ids. Unlinks 1-100 assets from the feed; it does not delete Asset resources. `rename_feed`: customer_id, asset_set_id, feed_name. Only the AssetSet name is updated. The AssetSet type is immutable. `attach_feed`: customer_id, asset_set_id, campaign_id. Links an existing PAGE_FEED to a DSA-enabled Search campaign. `detach_feed`: customer_id, asset_set_id, campaign_id. Unlinks the feed. If use_supplied_urls_only is true, first change that campaign setting to false with update_search_campaign. `delete_feed`: customer_id, asset_set_id, confirm=true. Removes an unlinked AssetSet. Detach every campaign first. Page Asset resources remain in the account. Use list_search_ads_entities with `list_dsa_page_feeds` and `list_dsa_page_feed_pages` before replacement, removal, detachment, or deletion. Create or replace CUSTOM_LABEL webpage targets through create_search_ads_entities / update_search_ads_entities after the feed is linked. Side effects and data handling: Execution records HireOtto usage and can consume 2 credits.
manage_dsa_page_feeds
Manage stored values used by ad customizers in responsive search ads. An RSA references an attribute using: {CUSTOMIZER.AttributeName:Inline fallback} Example RSA headline: Auto Loans From {CUSTOMIZER.AutoAPR:6.49%} This tool manages ad customizers and their stored values. Use `create_search_ads_entities` or `update_search_ads_entities` to create or edit the RSA itself. Value inheritance, from most specific to least specific: keyword -> ad_group -> campaign -> customer -> inline fallback Recommended workflow: 1. Review existing customizers using `list_search_ads_entities` with action="review_ad_customizers". 2. Create any missing attributes. 3. Set a customer-level default and narrower overrides where required. 4. Add {CUSTOMIZER.AttributeName:Fallback} to the relevant RSA. 5. Review again with expected_values for compliance-sensitive values. Actions: 1. create_attributes Create one or more attributes. Supported types are: TEXT, NUMBER, PRICE, and PERCENT. Preferred batch example: { "action": "create_attributes", "customer_id": "1234567890", "attributes": [ {"name": "AutoAPR", "type": "PERCENT"}, {"name": "MonthlyPayment", "type": "PRICE"}, {"name": "LoanTerm", "type": "NUMBER"}, {"name": "VehicleType", "type": "TEXT"} ], "validate_only": false } A single object is also accepted: { "attributes": {"name": "AutoAPR", "type": "PERCENT"} } A name-to-type object is also accepted: { "attributes": { "AutoAPR": "PERCENT", "MonthlyPayment": "PRICE" } } Native objects/lists are preferred. JSON strings containing the same structures are accepted when a client cannot send structured JSON. Attribute names are case-insensitively unique. Names and types cannot be edited after creation. Existing same-name/same-type attributes are returned unchanged. 2. set_values Create or replace scoped values. `values` accepts either one object or a list of objects. Each object requires: - attribute_name or attribute_id - scope - value - identifiers required by that scope Required identifiers: customer: no additional ID campaign: campaign_id ad_group: adgroup_id keyword: adgroup_id and criterion_id Example covering every scope: { "action": "set_values", "customer_id": "1234567890", "values": [ { "attribute_name": "AutoAPR", "scope": "customer", "value": "6.49%" }, { "attribute_name": "AutoAPR", "scope": "campaign", "campaign_id": "11111111111", "value": "5.99%" }, { "attribute_name": "AutoAPR", "scope": "ad_group", "adgroup_id": "22222222222", "value": "5.49%" }, { "attribute_name": "AutoAPR", "scope": "keyword", "adgroup_id": "22222222222", "criterion_id": "33333333333", "value": "4.99%" } ], "validate_only": false } A single value and attribute ID can also be used: { "values": { "attribute_id": "44444444444", "scope": "customer", "value": "6.25%" } } Value examples: TEXT: "Electric vehicles" NUMBER: "36" PRICE: "$299" or "USD299" PERCENT: "5.99%" Identical existing values are returned unchanged. Google represents scoped customizer values as create/remove resources rather than editable resources. Replacements therefore remove the old link and create the new link in separate requests. If creation fails, the action attempts to restore the previous value. 3. remove_values Remove one or more scoped values. Use the same identifying fields as set_values, but omit `value`. Example: { "action": "remove_values", "customer_id": "1234567890", "values": [ { "attribute_name": "AutoAPR", "scope": "campaign", "campaign_id": "11111111111" }, { "attribute_name": "AutoAPR", "scope": "ad_group", "adgroup_id": "22222222222" } ], "validate_only": false } A single removal and attribute ID are also accepted: { "values": { "attribute_id": "44444444444", "scope": "customer" } } Missing scoped values are returned unchanged as a no-op. After removal, Google may use the next broader value or the RSA's inline fallback. 4. remove_attribute Removing an attribute is guarded by a preview. Start with either its name or ID. Preview by name: { "action": "remove_attribute", "customer_id": "1234567890", "attribute_name": "AutoAPR" } Preview by ID: { "action": "remove_attribute", "customer_id": "1234567890", "attribute_id": "44444444444" } Review the returned values, RSA usages, inline fallbacks, and preview_hash. Then execute using the exact hash: { "action": "remove_attribute", "customer_id": "1234567890", "attribute_name": "AutoAPR", "confirm_removal": true, "preview_hash": "<exact hash returned by preview>", "allow_referenced_ads": true, "validate_only": false } `allow_referenced_ads=true` is required only when non-removed RSAs still reference the attribute. Use it only after reviewing every inline fallback. Validation notes: - Set validate_only=true to validate without intentionally changing the account. - Ordinary creates and removals can be fully validated by Google. - A replacement create cannot be fully validate-only checked while the existing scoped value still occupies the same resource identity. Inspect the returned validation_note for replacements. Side effects and data handling: Execution records HireOtto usage and can consume 5 credits.
manage_ad_customizers
Manage Google Ads bidding strategies. Use this tool when the user wants to inspect portfolio bidding strategies, create a portfolio bidding strategy, attach a campaign to a portfolio strategy, move a campaign back to standard campaign-level bidding, or remove an unused portfolio strategy. Actions ------- - 'list_bidding_strategies': List portfolio bidding strategies in the account. Optional args: - strategy_type: filter by type, e.g. TARGET_SPEND, TARGET_CPA - include_campaigns: true/false. If true, includes campaigns using each strategy. - 'list_campaigns_using_bidding_strategy': Show campaigns currently using one portfolio bidding strategy. Required args: bidding_strategy_id Optional args: - include_bidding_strategy: true/false. If true, includes strategy metadata. - 'create_portfolio_bidding_strategy': Create an account-level portfolio bidding strategy. Required args: name, strategy_type Optional args depend on strategy_type: - TARGET_SPEND: cpc_bid_ceiling - TARGET_CPA: target_cpa - TARGET_ROAS: target_roas - MAXIMIZE_CONVERSIONS: target_cpa - MAXIMIZE_CONVERSION_VALUE: target_roas - TARGET_IMPRESSION_SHARE: location, location_fraction, cpc_bid_ceiling - 'attach_portfolio_bidding_strategy': Move a campaign to an existing portfolio bidding strategy. Required args: campaign_id, bidding_strategy_id Notes: - This moves the campaign from standard bidding to portfolio bidding, or from one portfolio strategy to another. - Standard campaign-level bidding fields are no longer the active bidding surface once a portfolio strategy is attached. - 'set_standard_bidding_strategy': Set campaign-level standard bidding. Required args: campaign_id, strategy_type Optional args depend on strategy_type: - MANUAL_CPC: enhanced_cpc_enabled - TARGET_SPEND: cpc_bid_ceiling - MAXIMIZE_CONVERSIONS: target_cpa - MAXIMIZE_CONVERSION_VALUE: target_roas - TARGET_IMPRESSION_SHARE: location, location_fraction, cpc_bid_ceiling - 'detach_portfolio_and_create_dedicated_budget': Atomically move a campaign from portfolio bidding / shared-budget setup to a new standalone DAILY budget and standard campaign-level bidding. Required args: campaign_id, amount, strategy_type, name (new budget name) Optional args: - target_cpa - target_roas - cpc_bid_ceiling - enhanced_cpc_enabled - location - location_fraction Notes: - Use this when separate budget and bidding updates fail because the current portfolio strategy is aligned to the shared budget. - This creates a standalone/non-shared DAILY budget. - This clears campaign.bidding_strategy and sets standard campaign bidding in the same mutate request. - This is the safest way to split one campaign out of an aligned portfolio/shared-budget setup without an unsafe intermediate state. - 'link_portfolio_bidding_strategy_to_shared_budget': Link an existing portfolio bidding strategy to an existing shared budget. Required args: bidding_strategy_id, budget_id Notes: - Both entities must already exist. - The budget must be explicitly_shared=true. - This does not create the strategy or budget. - The budget and strategy should already be attached to the same campaign set, or both should have no campaigns attached. - This sets alignment on both the portfolio strategy and shared budget. Notes: - Use this to detach a campaign from portfolio bidding. - Google Ads standard bidding is set on the Campaign object. - Do not use bidding_strategy_type directly; it is read-only/reflective. - 'remove_bidding_strategy': Remove a portfolio bidding strategy. Required args: bidding_strategy_id Optional args: - allow_removal_if_assigned: defaults to false Notes: - By default, Otto refuses to remove strategies still assigned to campaigns. - Only use allow_removal_if_assigned=true when the user explicitly asks for it. - 'attach_campaign_to_aligned_budget_and_portfolio': Atomically attach a campaign to a shared budget and portfolio bidding strategy. Required args: campaign_id, budget_id, bidding_strategy_id Notes: - Use this when the budget and portfolio strategy are already linked/aligned, or when attaching only one side would fail due to alignment rules. - This updates campaign.campaign_budget and campaign.bidding_strategy in one campaign update. - The budget must be explicitly_shared=true. - If either entity is already aligned, it must be aligned to the other entity. - This does not create the budget or portfolio strategy. - This does not link the budget and strategy together. Use link_portfolio_bidding_strategy_to_shared_budget for that. Standard vs portfolio bidding ----------------------------- - Standard bidding belongs to one campaign and is set directly on campaign fields. - Portfolio bidding is an account-level BiddingStrategy object that can be shared across campaigns. - Moving from portfolio -> standard means clearing campaign.bidding_strategy and setting the standard campaign bidding field. - Moving from standard -> portfolio means setting campaign.bidding_strategy to an existing portfolio strategy resource. - Shared budget + portfolio bidding is not automatically aligned. Alignment is a separate relationship between a portfolio strategy and a shared budget. - When alignment exists, separate budget and bidding updates may fail because Google Ads expects both sides to remain consistent. - For an already aligned shared budget + portfolio strategy, attach campaigns with attach_campaign_to_aligned_budget_and_portfolio so both sides are updated together. Important gotchas ----------------- - Not every strategy works in every campaign type. - Some automated strategies have eligibility/data requirements. - Removing old/unused portfolio strategies is explicit, never automatic. - If a portfolio strategy becomes unused after a campaign is moved away, HireOtto reports it but does not remove it automatically. - If a campaign is in an aligned portfolio/shared-budget setup, use detach_portfolio_and_create_dedicated_budget to move it to standard bidding and a dedicated budget atomically. - link_portfolio_bidding_strategy_to_shared_budget should not be used to force unrelated campaign sets together. Align campaigns first. Args ---- action: One of the supported actions above. customer_id: Google Ads customer ID without hyphens. campaign_id: Required for attach_portfolio_bidding_strategy and set_standard_bidding_strategy. bidding_strategy_id: Required for list_campaigns_using_bidding_strategy, attach_portfolio_bidding_strategy, and remove_bidding_strategy. budget_id: Required for link_portfolio_bidding_strategy_to_shared_budget and attach_campaign_to_aligned_budget_and_portfolio. amount: New standalone daily budget amount for detach_portfolio_and_create_dedicated_budget. name: Portfolio strategy name for create_portfolio_bidding_strategy. strategy_type: Bidding strategy type. Examples: TARGET_SPEND, MAXIMIZE_CONVERSIONS, MAXIMIZE_CONVERSION_VALUE, TARGET_CPA, TARGET_ROAS. target_cpa: CPA target in account currency. target_roas: ROAS target as a ratio. Example: 3.5 means 350% ROAS. cpc_bid_ceiling: Max CPC ceiling in account currency where supported. enhanced_cpc_enabled: Used with MANUAL_CPC standard bidding. location: Used with TARGET_IMPRESSION_SHARE. One of ABSOLUTE_TOP_OF_PAGE, TOP_OF_PAGE, ANYWHERE_ON_PAGE. location_fraction: Impression share target. Accepts 0-1 or 0-100. include_campaigns: Used by list_bidding_strategies. include_bidding_strategy: Used by list_campaigns_using_bidding_strategy. allow_removal_if_assigned: Used by remove_bidding_strategy. Defaults to false. Returns ------- On success -> {"success": True, "action": "<action>", "data": ...} On error -> {"error": "...", "action": "<action>"} Side effects and data handling: Execution records HireOtto usage and can consume 1 credit for listing actions or 2 credits for write actions.
manage_bidding_strategies
Manage Google Ads campaign budgets. Use this tool when the user wants to inspect campaign budgets, create a standalone/shared budget, move a campaign to another budget, update budget amount/shareability, or remove an unused budget. Actions ------- - 'list_campaign_budgets' List campaign budgets in the account. Optional args: - include_campaigns: true/false. If true, includes campaigns using each budget. - 'list_campaigns_using_budget' Show campaigns currently using one budget. Required args: budget_id Optional args: - include_budget: true/false. If true, includes budget metadata. - 'create_campaign_budget' Create a budget without attaching it to a campaign. Required args: name, amount for DAILY budgets Optional args: - explicitly_shared: false = standalone/non-shared, true = shared - period: "DAILY" or "CUSTOM_PERIOD" - total_amount: total budget amount for CUSTOM_PERIOD budgets - 'update_campaign_budget' Update mutable fields on an existing budget. Required args: budget_id Optional args: amount, explicitly_shared Notes: - Budget name updates are not supported here. - Google Ads generally allows standalone -> shared in eligible cases. - Google Ads does not allow shared -> standalone. - 'attach_campaign_budget' Move an existing campaign to an existing budget. Required args: campaign_id, budget_id Notes: - Campaigns cannot have no budget. - "Detaching" a budget means replacing it with another budget. - This may leave the previous budget unused; Otto does not remove it automatically. - 'create_and_attach_campaign_budget' Create a new DAILY budget and attach it to an existing campaign. Required args: campaign_id, amount Optional args: name, explicitly_shared Use when the user wants to split a campaign out of a shared budget or give a campaign a new dedicated budget. For simple spend changes, prefer update_campaign_budget. - 'remove_campaign_budget' Remove a campaign budget. Required args: budget_id Optional args: - allow_removal_if_assigned: defaults to false Notes: - By default, HireOtto refuses to remove budgets still assigned to campaigns. - Only use allow_removal_if_assigned=true when the user explicitly asks for it. Shared vs standalone budgets ---------------------------- - explicitly_shared=false creates a standalone/non-shared budget. - explicitly_shared=true creates a shared budget. - DAILY budgets can be shared or standalone. - CUSTOM_PERIOD budgets cannot be shared. Important gotchas ----------------- - Replacing a campaign's budget can affect overdelivery/spend behavior. If the user only wants to change spend, update the current budget amount. - create_and_attach_campaign_budget creates DAILY budgets only. - CUSTOM_PERIOD budgets are campaign total budgets and have extra campaign eligibility constraints when attached. - Removing old/unused budgets is explicit, never automatic. Args ---- action: One of the supported actions above. customer_id: Google Ads customer ID without hyphens. campaign_id: Required for attach_campaign_budget and create_and_attach_campaign_budget. budget_id: Required for list_campaigns_using_budget, update_campaign_budget, attach_campaign_budget, and remove_campaign_budget. amount: Daily amount in account currency for DAILY budgets. Also used by create_and_attach_campaign_budget. name: Budget name for create_campaign_budget and create_and_attach_campaign_budget. explicitly_shared: true for shared budget, false for standalone/non-shared budget. period: "DAILY" or "CUSTOM_PERIOD". Only used by create_campaign_budget. total_amount: Total budget amount for CUSTOM_PERIOD budgets. include_campaigns: Used by list_campaign_budgets. include_budget: Used by list_campaigns_using_budget. allow_removal_if_assigned: Used by remove_campaign_budget. Defaults to false. Returns ------- On success -> {"success": True, "action": "<action>", "data": ...} On error -> {"error": "...", "action": "<action>"} Side effects and data handling: Execution records HireOtto usage and can consume 1 credit for listing actions or 2 credits for write actions.
manage_campaign_budgets
Manage Google Ads conversion actions. Supported actions ----------------- - 'create_conversion_action' Create a native Google Ads conversion action. Required args: - name Optional args: - conversion_action_type: WEBPAGE (default), UPLOAD_CLICKS, or UPLOAD_CALLS - category - counting_type: ONE_PER_CLICK or MANY_PER_CLICK - primary_for_goal - default_value - always_use_default_value - attribution_model Use WEBPAGE for a direct Google Ads website conversion. Creating it does not install or test the required website/GTM tag. UPLOAD_CLICKS is for offline imports, but Google recommends the Data Manager API for new integrations. - 'import_ga4_key_event' Import an existing key event from a linked GA4 property. Google Ads exposes unimported GA4 key events as HIDDEN conversion actions; this action finds the matching event and changes its status to ENABLED. Required args: - ga4_event_name Recommended args: - ga4_property_id (required when the same event name exists in multiple properties) Optional import settings: - name - category - primary_for_goal - default_value - always_use_default_value - 'update_conversion_action' Update mutable settings on an existing conversion action. Required args: - conversion_action_id Optional update args: - name String. New conversion action name. - status Conversion action status. Common values: - ENABLED - category Conversion action category. Common values: - DEFAULT - PAGE_VIEW - PURCHASE - SIGNUP - LEAD - DOWNLOAD - ADD_TO_CART - BEGIN_CHECKOUT - SUBSCRIBE_PAID - PHONE_CALL_LEAD - QUALIFIED_LEAD - BOOK_APPOINTMENT - REQUEST_QUOTE - CONTACT - SUBMIT_LEAD_FORM - OUTBOUND_CLICK - IMPORTED_LEAD - STORE_VISIT - STORE_SALE - DIRECTIONS - APP_INSTALL - APP_FIRST_OPEN - APP_PURCHASE - HOTEL_BOOKING - counting_type How conversions are counted. Values: - ONE_PER_CLICK - MANY_PER_CLICK - primary_for_goal Boolean. true = use as a primary/biddable conversion action where applicable. false = make it secondary/non-primary for goal optimization. - default_value Number. Default conversion value in account currency. Example: 75 means 75 in the account currency. - always_use_default_value Boolean. true = always use default_value, even if another value is sent. false = use default_value only when no dynamic value is provided. - attribution_model Attribution model. Common values: - GOOGLE_ADS_LAST_CLICK - GOOGLE_SEARCH_ATTRIBUTION_DATA_DRIVEN Important gotchas ----------------- - Creating a WEBPAGE action does not install tags or configure GTM. - import_ga4_key_event requires the GA4 property to already be linked and the event to already be marked as a key event in GA4. - include_in_conversions_metric is immutable in the Google Ads API. Use primary_for_goal to control primary/secondary bidding and reporting behavior. - Not every field is editable for every conversion action. - Editability can depend on conversion action type, origin, account ownership, and Google Ads eligibility rules. - type, origin, owner_customer, id, and resource_name are not updated here. - Changing primary_for_goal or attribution_model can affect bidding and reporting behavior. - When updating default_value, also set always_use_default_value if the user explicitly wants Google Ads to always use that value. Args ---- action: create_conversion_action, import_ga4_key_event, or update_conversion_action. customer_id: Google Ads customer ID without hyphens. conversion_action_id: Conversion action ID or resource name. conversion_action_type: WEBPAGE, UPLOAD_CLICKS, or UPLOAD_CALLS. ga4_property_id: Numeric GA4 property ID or properties/<id>. ga4_event_name: Exact, case-sensitive GA4 key event name. name: New conversion action name. status: ENABLED. category: Conversion action category. counting_type: ONE_PER_CLICK or MANY_PER_CLICK. primary_for_goal: Whether this action is primary/biddable where applicable. include_in_conversions_metric: Deprecated input; the API field is immutable. Use primary_for_goal. default_value: Default conversion value in account currency. always_use_default_value: Whether Google Ads should always use default_value. attribution_model: Attribution model, e.g. GOOGLE_ADS_LAST_CLICK or GOOGLE_SEARCH_ATTRIBUTION_DATA_DRIVEN. Returns ------- On success -> {"success": True, "action": "<action>", "data": ...} On error -> {"error": "...", "action": "<action>"} Side effects and data handling: This tool configures Google Ads conversion actions and activates already-exposed GA4 key events in Ads; it does not manage GA4 properties, install tags, or upload conversion events. Status, primary_for_goal and value changes can affect automated bidding. Removed conversion actions can be re-enabled. Execution records HireOtto usage and can consume 2 credits.
manage_conversion_actions
Manage Google Ads extension-style assets. Use this tool for sitelinks, callouts, structured snippets, call assets, and price assets. Actions: - list_extension_assets: List existing extension assets. Returns asset_resource_name values and active links. Use this before linking existing sitelinks/callouts/snippets/call/price assets. - create_extension_asset: Create one reusable extension asset. Requires asset_type and payload. Supported asset_type values: SITELINK, CALLOUT, STRUCTURED_SNIPPET, CALL, PRICE. Example SITELINK payload: { "name": "Pricing Sitelink", "link_text": "View Pricing", "description1": "Compare plans", "description2": "Choose your fit", "final_urls": ["https://example.com/pricing"], "final_mobile_urls": ["https://m.example.com/pricing"], "tracking_url_template": "{lpurl}?utm_source=google&utm_medium=cpc", "final_url_suffix": "utm_content=sitelink", "url_custom_parameters": {"assetflow": "extensions"}, "start_date": "2026-05-07", "end_date": "2026-05-20", "ad_schedule_targets": [ { "day_of_week": "MONDAY", "start_hour": 9, "start_minute": "ZERO", "end_hour": 17, "end_minute": "ZERO" } ] } Example CALLOUT payload: { "name": "Free Setup Callout", "callout_text": "Free setup", "start_date": "2026-05-07", "end_date": "2026-05-20" } Example STRUCTURED_SNIPPET payload: { "name": "Services Snippet", "header": "Services", "values": ["Audits", "Reporting", "Automation"] } Example CALL payload: { "name": "Main Sales Phone", "country_code": "US", "phone_number": "(800) 555-0100", "ad_schedule_targets": [ { "day_of_week": "MONDAY", "start_hour": 9, "start_minute": "ZERO", "end_hour": 17, "end_minute": "ZERO" } ] } Example PRICE payload: { "name": "Services Price Asset", "price_type": "SERVICES", "price_qualifier": "FROM", "language_code": "en", "currency_code": "USD", "price_offerings": [ { "header": "Audit", "description": "Account review", "final_url": "https://example.com/audit", "price": 49, "unit": "PER_MONTH" } ] } - link_extension_asset: Link an existing asset at customer, campaign, or ad group level. Requires level, asset_resource_name, field_type. Requires campaign_id when level="campaign". Requires adgroup_id when level="ad_group". - unlink_extension_asset: Remove an asset link from customer/campaign/ad group level. Requires level and link_resource_name. This removes the association only. The underlying asset remains reusable by asset_resource_name. Notes: - Create and link are separate on purpose. If the user asks to add new assets to a campaign, call create_extension_asset first, then link_extension_asset. - For reuse, call list_extension_assets first, pick the correct asset_resource_name, then link it. - Google Ads UI may show removed associations as Removed after unlinking. That is expected. Side effects and data handling: Execution records HireOtto usage and can consume 3 credits. CSV exports are temporarily stored in private storage and periodically deleted. Signed download links expire after the requested TTL; link expiry does not determine the file deletion time.
manage_extension_assets
Run account-level hygiene checks or fixes customer_id is required for all supported actions below. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) Action and Required / optional args mapping: `review_autotagging`- Review and Update auto tagging for the account: customer_id, **update** (bool, default=False) `review_conversion_tracking_setup` - Review conversion tracking status, conversion ownership, GA4 link evidence, and GA4 key events that are imported or available to import. `review_autoapply` - Review and disable auto-apply recommendation subscriptions for the account: customer_id, **disable** (bool, default=False) Note: Subscriptions with UNKNOWN types or invalid resource names cannot be disabled programmatically due to Google Ads API limitations and will be skipped. Of the 22 recommendations under auto-apply, 7 return the type UNKNOWN. `review_negative_keywords` - Review negative keywords at the ad group and campaign level: customer_id, campaign_id *(optional)* `get_all_disapproved_ads`: customer_id additional args: output_mode: - "summary": Return only inline rows (limited by `limit`) - default. - "summary_and_csv": Return inline rows + a signed CSV download URL (CSV limited by `export_limit`). - "csv_only": Return only the CSV export + minimal metadata (best for automation). limit: Max rows returned inline in `data` (default: 50). Use this when the user wants "top N" entities or a quick review without dumping huge outputs. export_limit: Max rows exported to CSV when output_mode includes CSV (default: 5000). Important: This also controls how many rows are fetched from Google Ads (via GAQL LIMIT), which helps avoid Render memory spikes on very large accounts. export_ttl_minutes: How long the signed CSV link remains valid (default: 30 minutes). Note: The link expires; the underlying file may remain stored until cleaned up by retention policy. Returns ------- Success → `{"success": True, "action": "<action>", "data": …}` Error → `{"error": "...", "action": "<action>"}` Example (enable auto-tagging if off) ------------------------------------ ```json { "action": "review_autotagging", "customer_id": "1234567890", "update": true } ``` Side effects and data handling: Optional updates enable auto-tagging, affecting click URLs, or pause automatic recommendation subscriptions; these settings can be changed again. Execution records HireOtto usage and can consume 3 credits. CSV exports are temporarily stored in private storage and periodically deleted. Signed download links expire after the requested TTL; link expiry does not determine the file deletion time.
account_review
List and inspect Google Search Console resources. Use this tool for Search Console setup/discovery and URL-level checks. Actions: - "list_sites": Lists Search Console properties available to the connected Google login. Use this first when the user has not provided a site_url. Returns site_url values like: - "sc-domain:example.com" - "https://www.example.com/" - "list_sitemaps": Lists submitted sitemaps for a Search Console property. Requires site_url. - "inspect_url": Checks Google's index status for a specific URL. Requires site_url and inspection_url. Use this when the user asks: - Is this page indexed? - Why is this URL not appearing in Google? - Check canonical / crawl / indexing status for this page. site_url: - Required for list_sitemaps and inspect_url. - Use a value from list_sites when possible. - Domain properties look like "sc-domain:example.com". - URL-prefix properties look like "https://www.example.com/". inspection_url: - Required only for inspect_url. - Must be a full URL, e.g. "https://www.example.com/pricing". - Even for domain properties, inspection_url must be a full URL. profile_id: - Optional. Use only when the user has connected multiple Search Console Google logins. If Search Console is not connected, call authenticate_search_console first. Side effects and data handling: Execution records HireOtto usage and can consume 5 credits.
search_console_resources
Update Demand Gen ad groups or ads. Supported actions: 1. action="update_ad_group" Updates Demand Gen ad group settings. Required: - customer_id - ad_group_id Optional: - ad_group_name - status - channel_strategy - selected_channels Accepted values: - status: - "PAUSED" - "ENABLED" - channel_strategy: - "ALL_CHANNELS" - "ALL_OWNED_AND_OPERATED_CHANNELS" - selected_channels: Dict/JSON object. Supported keys: - "youtube_in_stream" - "youtube_in_feed" - "youtube_shorts" - "discover" - "gmail" - "display" - "maps" Aliases accepted: - "shorts" -> "youtube_shorts" - "in_stream", "youtube in-stream", "youtube instream" -> "youtube_in_stream" - "in_feed", "youtube feed" -> "youtube_in_feed" Channel control notes: - At least one supported selected channel must be true. - Use either channel_strategy or selected_channels. Prefer selected_channels when the user specifies exact channels. 2. action="update_ad" Updates a Demand Gen ad status, or replaces creative by creating a new ad. Required: - customer_id - ad_group_id - ad_id Optional: - status - replace_creative - replacement_ad - pause_old_ad Accepted status values: - "PAUSED" - "ENABLED" Creative replacement: - Demand Gen creative fields are safest to change by replacement, not direct mutation. - Set replace_creative=True and pass replacement_ad as a dict or JSON string object. - replacement_ad should contain create_demand_gen_ad-style fields such as: ad_name, ad_type, final_urls, headlines, descriptions, business_name, call_to_action_text, image/video asset resource names, inline image URLs, youtube_video_ids, carousel_cards, etc. - pause_old_ad defaults to True so the old creative is paused after replacement. Recommended flow: - First call list_search_ads_entities(action="get_demand_gen_ad_group_settings") before changing ad group channel controls. - First call list_search_ads_entities(action="get_demand_gen_ads") before replacing ad creative. - Pass only the fields that should change. Side effects and data handling: Status values are forwarded to the Google Ads API enum, including REMOVED. Acceptance depends on the entity and Google Ads API restrictions; do not promise removal support solely because the enum accepts the value. Removal requests can be destructive and should only follow an explicit user request. Execution records HireOtto usage and can consume 2 credits for ad-group updates, 3 for ad-status updates, or 5 for creative replacement.
update_demand_gen_ads_entities
Update an existing Demand Gen campaign. Use this for campaign-level changes only. For ad group channel controls or ad creative/status updates, use update_demand_gen_ads_entities instead. Required: customer_id, campaign_id Optional campaign fields: - campaign_name - status - budget_id - campaign_goal - target_cpa - target_roas - target_cpc - remove_target_cpa - remove_target_roas - remove_target_cpc - start_date - end_date: pass "none" to remove the end date and run indefinitely - contains_eu_political_advertising - positive_geo_target_type - negative_geo_target_type - tracking_url_template - final_url_suffix - included_devices - ad_schedules - ad_schedule_update_mode Campaign goal / bidding: - campaign_goal accepted values: - "CONVERSIONS" - "CLICKS" - "CONVERSION_VALUE" - "YOUTUBE_ENGAGEMENTS" - target_cpa: optional amount in account currency. - target_roas: optional ROAS value, e.g. 3.5 for 350%. - target_cpc: optional amount in account currency. - remove_target_cpa, remove_target_roas, remove_target_cpc: true/false flags to remove existing target values where supported. - Changing campaign_goal may also change the bidding strategy. - campaign_goal="YOUTUBE_ENGAGEMENTS" may update campaign conversion goals if matching YouTube engagement goals exist in the account. Accepted values: - status: - "PAUSED" - "ENABLED" - contains_eu_political_advertising: - "DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING" - "CONTAINS_EU_POLITICAL_ADVERTISING" - positive_geo_target_type: - "PRESENCE" - "PRESENCE_OR_INTEREST" - negative_geo_target_type: - "PRESENCE" - included_devices: - "DESKTOP" - "MOBILE" - "TABLET" - "CONNECTED_TV" Omit included_devices to leave device targeting unchanged. - ad_schedule_update_mode: - "REPLACE" - "APPEND" Use REPLACE carefully because it removes existing ad schedules before adding the provided schedules. - ad_schedules: List of dicts or JSON string list. Each item may include: - day_of_week: "MONDAY"..."SUNDAY" - start_hour: 0-23 - end_hour: 0-23 - start_minute: "ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE" - end_minute: "ZERO", "FIFTEEN", "THIRTY", "FORTY_FIVE" Device targeting: - included_devices accepts DESKTOP, MOBILE, TABLET, CONNECTED_TV. - Omit included_devices to leave device targeting unchanged. - Device criteria should not be removed; the underlying action updates device bid modifiers to include/exclude devices. Ad schedules: - ad_schedules can be a list of schedule dicts or a JSON string list. - ad_schedule_update_mode defaults to REPLACE when schedules are provided. - Be careful with schedule replacement because it can remove existing schedules. Recommended flow: - First call list_search_ads_entities(action="get_demand_gen_campaign_settings") to inspect current settings. - Then call this tool with only the fields the user wants changed. Side effects and data handling: Status values are forwarded to the Google Ads API enum, including REMOVED. Acceptance depends on the entity and Google Ads API restrictions; do not promise removal support solely because the enum accepts the value. Removal requests can be destructive and should only follow an explicit user request. Execution records HireOtto usage and can consume 3 credits.
update_demand_gen_campaign
Update Search campaign settings, account/campaign URL tracking settings, targeted networks, or the EU political advertising declaration. This tool does not support VIDEO campaigns. The Google Ads API permits fetching and reporting on existing VIDEO campaigns, but not updating their campaign settings. customer_id is required for all supported actions below. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) For action-specific campaign arguments: * `campaign_id` is used only by `update_settings` and `update_networks` * `campaign_ids` is used only by `update_eu_political_advertising_declaration` * `update_customer_tracking` does not require campaign_id * `update_settings` and `update_networks` currently support one campaign at a time * `update_eu_political_advertising_declaration` supports bulk updates Actions and Arguments mapping: `update_settings`: customer_id, campaign_id **plus** at least one of the optional setting fields: * name – new campaign name * status – "PAUSED" | "ENABLED" The implementation also forwards "REMOVED"; Google Ads API restrictions apply. * positive_geo_target_type - "PRESENCE" | "PRESENCE_OR_INTEREST" (called geo targeting type in most cases) * start_date – "YYYYMMDD" * end_date – "YYYYMMDD", or "none" to remove the end date and run indefinitely * tracking_url_template – campaign-level tracking template. Example: "{lpurl}?utm_source=google&utm_campaign={campaignid}" * final_url_suffix – query parameters appended to the landing-page URL. Do not include a leading "?". Example: "utm_source=google&utm_medium=cpc" * url_custom_parameters – complete replacement object/list of custom parameters. Preferred object format: {"campaign": "summer_sale", "source": "google"} Keys are passed without the leading underscore. Reference them inside URLs as "{_campaign}" and "{_source}". Maximum 8 parameters. Keys must be alphanumeric. * URL tracking update behavior: - Omit a field to leave it unchanged. - Pass "" to clear tracking_url_template or final_url_suffix. - Pass {} or [] to clear all url_custom_parameters. * dynamic_search_ads_setting – update or enable DSA campaign settings. Accepts any changed fields from domain_name, language_code, and use_supplied_urls_only. When enabling DSA for the first time, domain_name and language_code are required together. `use_supplied_urls_only=true` is reserved for campaigns that have a DSA page feed attached. * budget_id + budget_amount – pass **both** to change budget * ad_serving_optimization_status – "OPTIMIZE" | "CONVERSION_OPTIMIZE" | "ROTATE" | "ROTATE_INDEFINITELY" * bidding_strategy_type - str. Allowed values: "MANUAL_CPC", "MAXIMIZE_CONVERSIONS", "MAXIMIZE_CONVERSION_VALUE", "TARGET_IMPRESSION_SHARE", "TARGET_SPEND" TARGET_SPEND - called 'Maximise Clicks' in Google Ads UI * target_cpa - float. Compatible with: "MAXIMIZE_CONVERSIONS" * target_roas - float. Compatible with: "MAXIMIZE_CONVERSION_VALUE" * impression_location - string. Required with: "TARGET_IMPRESSION_SHARE". Allowed values: "ABSOLUTE_TOP_OF_PAGE", "TOP_OF_PAGE", "ANYWHERE_ON_PAGE" * location_fraction - float. Required with: "TARGET_IMPRESSION_SHARE". * cpc_bid_ceiling - float. Compatible with: "TARGET_IMPRESSION_SHARE", "TARGET_SPEND". Required for "TARGET_IMPRESSION_SHARE" * criterion_updates – list:[{"criterion_id": "<id>", "bid_modifier": <float>}] bid_modififer: Adjusts the bid for this criterion. `1.2` means 20% increase, `0.8` means 20% decrease. Applies to DEVICE, LOCATION, and AD_SCHEDULE. Use 0 to opt out of a Device type. `update_customer_tracking`: customer_id plus at least one of: * tracking_url_template * final_url_suffix This updates the account-level URL tracking defaults. Omit a field to leave it unchanged. Pass "" to clear it. Account-level url_custom_parameters are not supported. `update_networks`: customer_id, campaign_id, target_search_network **and** target_content_network (both need to passed) target_search_network - called "Google search partners" in Google Ads UI target_content_network - called "Google display network" in Google Ads UI `update_eu_political_advertising_declaration`: customer_id, campaign_ids, eu_political_advertising_status * campaign_ids - list of campaign IDs to update. Can be a JSON string list or native list. * eu_political_advertising_status - "CONTAINS_EU_POLITICAL_ADVERTISING" | "DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING" * Use this to declare one or more campaigns that are currently undeclared for EU political advertising. * This action only updates the campaign's EU political advertising declaration. # create_search_ads_entities / update_search_campaign / update_search_ads_entities If action fails because of undeclared EU political advertising status, call `update_search_campaign` with action `update_eu_political_advertising_declaration` for the affected campaign(s), then retry. Returns ------- • Success → `{"success": True, "action": "<action>", "data": ...}` • Error → `{"error": "...", "action": "<action>"}` Example (pause campaign & raise device bid) ------------------------------------------- ```json { "action": "update_settings", "customer_id": "1234567890", "campaign_id": "111222333", "status": "PAUSED", "criterion_updates": [ {"criterion_id": "999888777", "bid_modifier": 1.25} ] } ``` Example (clear a campaign end date) ----------------------------------- ```json { "action": "update_settings", "customer_id": "1234567890", "campaign_id": "111222333", "end_date": "none" } ``` Example (set campaign URL tracking) ----------------------------------- ```json { "action": "update_settings", "customer_id": "1234567890", "campaign_id": "111222333", "tracking_url_template": "{lpurl}?utm_source=google&utm_campaign={_campaign}", "final_url_suffix": "utm_medium=cpc", "url_custom_parameters": { "campaign": "summer_sale" } } ``` Example (clear account-level tracking defaults) ------------------------------------------------ ```json { "action": "update_customer_tracking", "customer_id": "1234567890", "tracking_url_template": "", "final_url_suffix": "" } ``` Example (declare campaign as not containing EU political advertising) ------------------------------------------- ```json { "action": "update_eu_political_advertising_declaration", "customer_id": "1234567890", "campaign_ids": ["111222333", "444555666"], "eu_political_advertising_status": "DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING" } ``` Side effects and data handling: Status values are forwarded to the Google Ads API enum, including REMOVED. Acceptance depends on the entity and Google Ads API restrictions; do not promise removal support solely because the enum accepts the value. Removal requests can be destructive and should only follow an explicit user request. Execution records HireOtto usage and can consume 2 credits.
update_search_campaign
Unified update endpoint for Search Ads entities and ad-level URL settings. Most actions in this tool are Search-specific. However, `update_ad_details` can also update the top-level final URL and URL tracking fields of an existing Demand Gen ad. This preserves the same ad resource instead of replacing the Demand Gen creative. customer_id is required for all supported actions below. If the user didn’t provide customer_id: 1) Call `list_accessible_accounts(refresh=false)` to get the saved accounts. 2) If the list has exactly 1 account, use that customer_id silently. 3) If it has multiple accounts, list out the accounts with {descriptive_name} ({customer_id}) and ask the user to pick one. 4) If the list is empty, it means google ads isn't properly authenticated. use `authenticate_google_ads` (to connect) Action and Required Arguments mapping: `update_adgroup`: customer_id, campaign_id, adgroup_id, plus at least one field: status, adgroup_name, cpc_bid, tracking_url_template, final_url_suffix, or url_custom_parameters. status: Allowed values include "PAUSED" | "ENABLED" | "REMOVED" (adgroup / ad) URL field behavior: - Omit a field to leave it unchanged. - Pass "" to clear tracking_url_template or final_url_suffix. - Pass {} or [] to clear all url_custom_parameters. `update_keyword_status`: customer_id, adgroup_id, keyword_criterion_ids, keyword_status keyword_status: Allowed values include "PAUSED" | "ENABLED" | "REMOVED" `update_ad_status`: customer_id, adgroup_id, ad_id, status Dynamic Search Ad update behavior: * Existing DSA creative and ad-level URL fields are immutable. * Use `update_ad_status` to enable, pause, or remove a DSA. * Use `update_adgroup` for inherited tracking_url_template and other supported ad-group URL settings. * To change descriptions or an ad-level tracking override, create a new paused DSA and remove the old DSA after reviewing it. `update_dynamic_target`: customer_id, adgroup_id, criterion_id plus at least one of status, cpc_bid, or URL tracking fields. Use status="REMOVED" to remove a target. REMOVED must be used alone; do not combine it with cpc_bid or URL tracking fields. `replace_dynamic_target`: customer_id, adgroup_id, criterion_id plus criterion_name and/or conditions. Use this when changing the target definition because Google makes those fields create-only. Other target settings are preserved and the replacement is atomic. CUSTOM_LABEL conditions are supported when the label exists in a page feed linked to the campaign. `update_ad_details`: customer_id, ad_id plus at least one supported field. (Do not use this action for Dynamic Search Ads. Existing DSAs cannot be modified through AdService.) Ad-level URL fields supported for both Search and Demand Gen ads: * new_final_url – replaces the top-level final URL. * new_final_mobile_url – replaces the top-level mobile final URL. * tracking_url_template * final_url_suffix * url_custom_parameters Important Demand Gen behavior: * Despite this tool's `update_search_ads_entities` name, use `action="update_ad_details"` to update an existing Demand Gen ad's top-level final URL or URL tracking fields. * The existing Demand Gen ad resource and ad ID are retained. * This does not update the final URLs of individual carousel-card assets. URL field behavior: * Omit a field to leave it unchanged. * Pass "" to clear tracking_url_template or final_url_suffix. * Pass {} or [] to clear all url_custom_parameters. * url_custom_parameters is a complete replacement, not a partial merge. * Custom parameter keys are passed without a leading underscore. For example, pass {"campaign": "summer"} and reference it as "{_campaign}" in the tracking template. Search responsive-ad creative fields: Fetch existing headlines/descriptions via list_ads and reconstruct complete new_headlines/new_descriptions list (add/remove/modify as needed) since this replaces all headlines/descriptions. new_headlines: (dict or list): Headlines to be used in the ad. • If a dict is provided, keys are headline texts and values are pin fields (e.g., "HEADLINE_1"). • If a list is provided, no pinning is applied. Must have at least 3 and at most 15 headlines. Each headline must be ≤ 30 characters. new_descriptions (dict or list): Descriptions for the ad. • If a dict is provided, keys are description texts and values are pin fields (e.g., "DESCRIPTION_1"). • If a list is provided, no pinning is applied. Must have at least 2 and at most 4 descriptions. Each description must be ≤ 90 characters. new_path1 and new_path2: Optional display URL paths. Must be ≤ 15 characters if provided. Use empty strings only if intentionally clearing paths. new_headlines, new_descriptions, new_path1 and new_path2 apply to responsive Search ads. Do not use those creative fields for Demand Gen ads. `add_keywords_to_negative_list`: customer_id shared_set_id: Use `list_negative_keyword_lists` action under `list_search_ads_entities` tool to fetch existing lists. keywords: • If array: ["employment", "jobs", ...] –> all will use `match_type`. • If object: {"employment": "BROAD", "jobs": "PHRASE", ...} • *Preferred* → array or object. *Also accepted* → the same JSON **as a string**; it will be decoded. match_type (str, optional): A single match type for all keywords if keywords is provided as a list. Example values include "BROAD", "PHRASE", or "EXACT". `remove_keywords_from_negative_list`: customer_id shared_set_id: Use `list_negative_keyword_lists` with `include_keywords=true` under `list_search_ads_entities` to fetch the list and criterion resource names. Provide exactly one of: • resource_names: one criterion resource name or an array of names returned by `list_negative_keyword_lists` / `add_keywords_to_negative_list`. • keywords: an object such as {"employment": "BROAD", "jobs": "PHRASE"}, or an array plus one match_type for all entries. Keyword text matching is case-insensitive but match type must also match. `assign_negative_list_to_campaign`: customer_id, campaign_id, shared_set_id `add_negative_keywords_to_campaign`: (Add NEGATIVE keywords at the campaign level to exclude these terms across all ad groups in the campaign.) customer_id, campaign_id, keywords, (match_type) keywords and match_type similar as described above. `set_keyword_bid`: customer_id, adgroup_id, keyword_criterion_ids, cpc_bid Sets the same explicit max CPC bid on one or more positive keywords. cpc_bid is expressed in the account currency. The containing campaign must use MANUAL_CPC. This action never changes the campaign bidding strategy. If action fails because of undeclared EU political advertising status, call `update_search_campaign` with action `update_eu_political_advertising_declaration` for the affected campaign(s), then retry. Returns ------- Success → `{"success": True, "action": "<action>", "data": …}` Error → `{"error": "...", "action": "<action>"}` Example (pause two keywords) ---------------------------- ```json { "action": "update_keyword_status", "customer_id": "1234567890", "adgroup_id": "444333222", "keyword_criterion_ids": ["111", "222"], "keyword_status": "PAUSED" } ``` Example (update Search ad destination and tracking) --------------------------------------------------- ```json { "action": "update_ad_details", "customer_id": "1234567890", "ad_id": "777888999", "new_final_url": "https://example.com/new-page", "tracking_url_template": "{lpurl}?utm_campaign={_campaign}", "final_url_suffix": "utm_source=google&utm_medium=cpc", "url_custom_parameters": { "campaign": "brand_search" } } ``` Example (update an existing Demand Gen ad's top-level final URL) ---------------------------------------------------------------- ```json { "action": "update_ad_details", "customer_id": "1234567890", "ad_id": "777888999", "new_final_url": "https://example.com/new-demand-gen-page" } ``` Example (clear ad-level tracking overrides) ------------------------------------------- ```json { "action": "update_ad_details", "customer_id": "1234567890", "ad_id": "777888999", "tracking_url_template": "", "final_url_suffix": "", "url_custom_parameters": {} } ``` Side effects and data handling: Execution records HireOtto usage and can consume 2 credits.
update_search_ads_entities
Add, attach, remove, or update Performance Max assets / asset groups.
update_pmax_assets
Add or remove Performance Max audience signals and search themes on an existing asset group.
update_pmax_signals
Find weekly Google Ads optimization opportunities using mature performance data. Use this Google Ads analysis after enough data has accumulated for optimization decisions. It compares enabled-campaign performance with a prior period, reviews Search impression share, and runs focused queries for search terms, enabled keywords, and responsive search ads. Candidate rows are filtered and limited at query time, then collated into severity-ranked findings with evidence, CSV exports, and suggested follow-up tools. The audit can identify possible negative keywords, converting queries that may deserve their own keyword, underperforming keywords, Manual CPC bid-review candidates, disapproved ads, and ads performing below their ad-group CTR. Recommendations are review candidates, not automatic changes.
weekly_optimization_audit
How do I improve a ChatGPT Plugin's 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 HireOtto Performance Ads alternatives on ChatGPT?
As of 2026-09-26, HireOtto Performance Ads competes with Ad Superpowers, AdKit - Ads Manager, AdPage, adplane, AdsAgent, Adspirer, Adszy, AgencyAnalytics, Agentio, Billy Grace Insights, Channel99, DashThis, Data Bloo, Delivra, Dynamoi, Flyweel, Groas, HYPD AI - Paid Ads & Analytics, Hyros, Jepto, Kreel, Lead Recorder, Lily Apple Ads, LoomaScale, Markifact - Ads & Analytics, Masha, Metadata, Momently, Nexoya, Optmyzr, PaidSync, Reportei, Roivenue, StoreAdOps, Supermetrics, Tap, Triple Whale, Voluum, Wask, Whatagraph, Windsor.ai Facebook Ads, Windsor.ai Google Ads, Windsor.ai TikTok Ads 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.