tva
← Insights

Google Ads API: การตั้งค่า การยืนยันตัวตน การอ่านและการเขียนข้อมูล

คู่มือทางเทคนิคสำหรับการตั้งค่าการเข้าถึง Google Ads แบบโปรแกรม — ตั้งแต่สถาปัตยกรรมไปจนถึงการเรียก API ครั้งแรก ครอบคลุมการกำหนดค่า MCC, OAuth 2.0, ระดับ Developer Token, ไลบรารี google-ads สำหรับ Python, การอ่านข้อมูลด้วย GAQL และรูปแบบการเขียนแบบ validate_only

สถาปัตยกรรม

จำเป็นต้องมีองค์ประกอบสามอย่างแยกกันก่อนที่การเรียก API ครั้งเดียวจะทำงานได้:

องค์ประกอบวัตถุประสงค์ตัวอย่าง
**Manager Account (MCC)**ออก Developer Token`login_customer_id`
**Google Cloud Project**OAuth 2.0 client สำหรับการยืนยันตัวตนClient ID + Secret
**Google Ads Account**เป้าหมายของการดำเนินการ API ทั้งหมด`customer_id`

องค์ประกอบเหล่านี้ไม่ใช่บัญชีเดียวกัน MCC สามารถเป็นเจ้าของ Developer Token ได้โดยไม่ต้องเป็นเจ้าของบัญชีเป้าหมาย — เพียงแค่ต้องเชื่อมโยงในฐานะผู้จัดการ Google Cloud Project สามารถอยู่ภายใต้ตัวตน Google ที่ต่างจาก MCC บัญชีเป้าหมายคือบัญชีผู้โฆษณาที่แคมเปญอาศัยอยู่

การแยกส่วนนี้มีความสำคัญเนื่องจาก API Center (ที่ซึ่ง Developer Token ถูกออกให้) มีให้ใช้งานเฉพาะภายใน Manager Accounts เท่านั้น บัญชี Google Ads แบบเดี่ยวไม่สามารถเข้าถึง API Center ได้ แม้ว่าจะมีผู้ใช้ระดับผู้ดูแลระบบก็ตาม

ส่วนหัวของคำขอ API จะประกอบรวมตัวตนทั้งสามนี้พร้อมกับ OAuth Bearer token:

developer-token: <from MCC API Center>
login-customer-id: <MCC numeric ID, no dashes>
customer-id: <target account numeric ID>
Authorization: Bearer *** 2.0 access token>

ข้อกำหนดเบื้องต้น

  • Google Ads Manager Account ที่ตั้งค่าเสร็จสมบูรณ์แล้ว
  • บัญชีโฆษณาเป้าหมายที่เชื่อมโยงกับ Manager Account และยอมรับการเชื่อมโยงแล้ว
  • Google Cloud Project ที่เปิดใช้งาน Google Ads API แล้ว
  • Python 3.9+ พร้อมไลบรารี google-ads (pip install google-ads)
  • เบราว์เซอร์สำหรับขั้นตอน OAuth consent แบบครั้งเดียว

ขั้นตอนที่ 1: Manager Account และ Developer Token

API Center อยู่ภายใต้ Tools & Settings → Setup → API Center ภายใน Manager Account หากไม่พบ API Center แสดงว่าบัญชีนั้นไม่ใช่ Manager Account หรือการตั้งค่ายังไม่สมบูรณ์

จาก API Center ให้ขอ Developer Token ตั้งค่าประเภทบัญชีเป็น Advertiser (ไม่ใช่ Agency หรือ Third-Party) เมื่อ token นั้นมีไว้สำหรับบัญชีของคุณเอง Token จะถูกออกให้ทันทีในระดับ Test Access

Test Access อนุญาตให้:

  • ดำเนินการอ่านกับบัญชีที่เชื่อมโยงใด ๆ
  • ดำเนินการเขียนกับ บัญชีทดสอบเท่านั้น
  • ไม่อนุญาตให้ดำเนินการเขียนกับบัญชีจริง (production)
  • ข้อผิดพลาดสำหรับการเขียนกับบัญชีจริงด้วย Test Access คือ RESOURCE_NOT_FOUND — ไม่ใช่ PERMISSION_DENIED ซึ่งอาจทำให้สับสนเนื่องจากทรัพยากรนั้นมีอยู่จริงและสามารถอ่านได้ ข้อผิดพลาดนี้หมายความว่า API ปฏิเสธที่จะดำเนินการ mutation ภายใต้ระดับการเข้าถึงปัจจุบัน

    การสมัคร Basic Access

    หากต้องการเขียนกับบัญชีจริง ให้สมัคร Basic Access จากหน้า API Center เดียวกัน แบบฟอร์มการสมัครประกอบด้วยคำถาม 12 ข้อ สำหรับการใช้งานภายในกับบัญชีของคุณเอง คำตอบที่เกี่ยวข้องคือ:

    คำถามคำตอบ
    Q4: ความสัมพันธ์กับ Google RepresentativeNo
    Q6: Business Modelอธิบายกรณีการใช้งานของคุณเอง (e-commerce, lead gen, internal reporting)
    Q8: ใครจะมีสิทธิ์เข้าถึงInternal users — เฉพาะพนักงานเท่านั้น
    Q9: เครื่องมือที่พัฒนาโดยบุคคลที่สามNo (สคริปต์/เอเจนต์ของตัวเอง)
    Q10: Conversion Tracking & Remarketing APINo (เว้นแต่คุณจะใช้งานจริง)
    Q11: ประเภทแคมเปญSearch, Performance Max, Shopping (ตามที่เกี่ยวข้อง)
    Q12: ความสามารถCampaign Creation, Campaign Management, Reporting

    จำเป็นต้องมีเอกสารออกแบบ (PDF) สำหรับ Q7 ซึ่งควรอธิบายสถาปัตยกรรม API, ขั้นตอนการยืนยันตัวตน, กลยุทธ์การจำกัดอัตราการเรียก (rate-limiting), การจัดการข้อผิดพลาด และกรณีการใช้งานภายในเท่านั้น ให้เขียนตามข้อเท็จจริง — ทีมตรวจสอบ compliance จะประเมินความสอดคล้องกับกรณีการใช้งานที่แจ้งไว้

    ระยะเวลาดำเนินการ ณ เดือนมิถุนายน 2026: ประมาณ 3 วันทำการ พร้อมหมายเหตุเกี่ยวกับปริมาณการสมัครที่สูงกว่าปกติ

    ขั้นตอนที่ 2: OAuth 2.0

    การตั้งค่า Google Cloud Project

    ใน Google Cloud Console ภายใต้โปรเจกต์ที่เกี่ยวข้อง:

    1. เปิดใช้งาน Google Ads API (APIs & Services → Library)
    2. กำหนดค่า OAuth consent screen:
  • User Type: Internal (เฉพาะผู้ใช้ใน Google Workspace ของคุณเท่านั้นที่สามารถอนุญาต — ข้ามการตรวจสอบแอปภายนอก)
  • ชื่อแอป, อีเมลสนับสนุน, อีเมลผู้ติดต่อนักพัฒนา
  • เพิ่ม scope ภายใต้ Data Access: https://www.googleapis.com/auth/adwords
  • สร้าง OAuth Client ID:
  • Application type: Desktop app
  • ดาวน์โหลด client secret JSON
  • ประเภท Desktop app ใช้ http://localhost เป็น redirect URI ซึ่งถูกต้อง — ขั้นตอน OAuth จะเปิดเบราว์เซอร์, Google จะเปลี่ยนเส้นทางไปยัง localhost พร้อม authorization code และ HTTP server ในเครื่องจะดักจับค่านั้น

    การสร้าง Refresh Token

    สคริปต์ Python ที่รัน HTTP server ในเครื่องบน 127.0.0.1:0 (พอร์ตสุ่ม), แสดง authorization URL, รอคำขอหนึ่งรายการ, ดึงพารามิเตอร์ code และแลกเปลี่ยนเป็น tokens:

    from pathlib import Path
    from http.server import HTTPServer, BaseHTTPRequestHandler
    from urllib.parse import urlparse, parse_qs
    from google_auth_oauthlib.flow import Flow
    
    class CallbackHandler(BaseHTTPRequestHandler):
        code_value = None
        def do_GET(self):
            qs = parse_qs(urlparse(self.path).query)
            CallbackHandler.code_value = (qs.get('code') or [None])[0]
            self.send_response(200)
            self.end_headers()
            self.wfile.write(b'OAuth complete.')
        def log_message(self, format, *args):
            return
    
    server = HTTPServer(('127.0.0.1', 0), CallbackHandler)
    redirect_uri = f'http://127.0.0.1:{server.server_port}/'
    flow = Flow.from_client_secrets_file(
        'client_secret.json',
        scopes=['https://www.googleapis.com/auth/adwords'],
        redirect_uri=redirect_uri
    )
    auth_url, _ = flow.authorization_url(
        access_type='offline',
        prompt='consent'
    )
    print(auth_url)
    server.handle_request()
    flow.fetch_token(code=CallbackHandler.code_value)
    Path('google_ads_token.json').write_text(flow.credentials.to_json())

    พารามิเตอร์สองตัวที่มีความสำคัญ:

  • access_type='offline' — ส่งคืน refresh token ไม่ใช่แค่ access token
  • prompt='consent' — บังคับให้แสดงหน้าจอ consent ใหม่แม้ว่าผู้ใช้จะเคยอนุญาตแล้วก็ตาม จำเป็นเพื่อรับ refresh token ใหม่หากมีการเปลี่ยนแปลง scopes
  • refresh token จะคงอยู่ถาวรเว้นแต่จะถูกเพิกถอน, ผู้ใช้เปลี่ยนรหัสผ่าน, หรือ token ไม่ถูกใช้งานเป็นเวลา 6 เดือน

    ปัญหา Scope กับ Clients ที่มีอยู่เดิม

    หาก OAuth client เคยได้รับอนุญาตสำหรับ scopes อื่นมาก่อน (Gmail, Drive, Calendar) Google จะส่งคืนผลรวมของ scopes เดิมและใหม่ ไลบรารี google-auth-oauthlib จะปฏิเสธความไม่ตรงกันของ scope นี้โดยค่าเริ่มต้น ให้ตั้งค่าตัวแปรสภาพแวดล้อมก่อนโหลด flow:

    import os
    os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'

    อีกทางเลือกหนึ่งคือละเว้น include_granted_scopes=true จาก authorization URL ซึ่งจะบอกให้ Google ขอเฉพาะ scope ที่ระบุอย่างชัดเจนเท่านั้น

    ขั้นตอนที่ 3: `google-ads.yaml`

    ไลบรารีอ่านการกำหนดค่าจากไฟล์ YAML:

    developer_token: <value>
    client_id: <value>
    client_secret: <value>
    refresh_token: <value>
    login_customer_id: 1911599764
    use_proto_plus: true

    กฎความปลอดภัย:

  • สิทธิ์ของไฟล์: 0600 (เจ้าของอ่าน/เขียนเท่านั้น)
  • ห้าม commit เข้า version control
  • เก็บไว้นอก Git repository ใด ๆ
  • สำหรับการตั้งค่าแบบทีม ให้แจกจ่ายผ่าน secrets manager ไม่ใช่ไฟล์ที่แชร์ร่วมกัน
  • login_customer_id คือ MCC ID ที่เป็นตัวเลขโดยไม่มีขีดคั่น มันบอก API ว่าจะใช้ Developer Token ของบัญชีผู้จัดการใด customer_id เป้าหมายจะถูกส่งตอนเรียกใช้ API ไม่ได้อยู่ในไฟล์กำหนดค่า

    use_proto_plus: true เปิดใช้งานอินเทอร์เฟซ protobuf-plus ซึ่งจำเป็นสำหรับ API เวอร์ชันปัจจุบัน

    ขั้นตอนที่ 4: การเริ่มต้น Python Client

    from google.ads.googleads.client import GoogleAdsClient
    
    client = GoogleAdsClient.load_from_storage(
        '/path/to/google-ads.yaml',
        version='v22'
    )
    gs = client.get_service('GoogleAdsService')

    พารามิเตอร์ version เลือกเวอร์ชัน API อย่างชัดเจน ไลบรารี google-ads มาพร้อมกับหลายเวอร์ชันที่ติดตั้งแบบขนาน (v19 ถึง v22 ณ เดือนมิถุนายน 2026) ควรระบุเวอร์ชันเสมอ — ค่าเริ่มต้นอาจล้าหลังหรือไม่รองรับฟิลด์ใหม่กว่า

    ตรวจสอบการเชื่อมต่อ:

    cs = client.get_service('CustomerService')
    customers = cs.list_accessible_customers()
    ids = [r.split('/')[-1] for r in customers.resource_names]
    # Example output: ['1305475941', '3977581086', '1911599764']

    ขั้นตอนที่ 5: การดำเนินการอ่าน (GAQL)

    Google Ads ใช้ GAQL (Google Ads Query Language) ซึ่งเป็นไวยากรณ์คล้าย SQL การดำเนินการอ่านทั้งหมดผ่าน GoogleAdsService.search_stream() ซึ่งหลีกเลี่ยงการแบ่งหน้า (pagination) และเป็นที่แนะนำมากกว่า search() สำหรับคำถามส่วนใหญ่

    แคมเปญพร้อมเมตริกประสิทธิภาพ

    SELECT
      campaign.id,
      campaign.name,
      campaign.status,
      campaign.advertising_channel_type,
      campaign.serving_status,
      campaign.bidding_strategy_type,
      metrics.impressions,
      metrics.clicks,
      metrics.cost_micros,
      metrics.conversions,
      metrics.conversions_value,
      metrics.ctr,
      metrics.average_cpc
    FROM campaign
    ORDER BY campaign.id

    งบประมาณแคมเปญ

    SELECT
      campaign_budget.id,
      campaign_budget.name,
      campaign_budget.amount_micros,
      campaign_budget.delivery_method,
      campaign_budget.status,
      campaign.id,
      campaign.name
    FROM campaign_budget

    กลุ่มโฆษณา

    SELECT
      ad_group.id,
      ad_group.name,
      ad_group.status,
      ad_group.cpc_bid_micros,
      campaign.id,
      campaign.name
    FROM ad_group
    ORDER BY campaign.id, ad_group.id

    คีย์เวิร์ด (เรียงตาม Impressions)

    SELECT
      ad_group_criterion.keyword.text,
      ad_group_criterion.keyword.match_type,
      ad_group_criterion.status,
      ad_group_criterion.criterion_id,
      ad_group.id,
      ad_group.name,
      campaign.id,
      campaign.name,
      metrics.impressions,
      metrics.clicks,
      metrics.cost_micros,
      metrics.conversions
    FROM keyword_view
    WHERE ad_group_criterion.type = 'KEYWORD'
    ORDER BY metrics.impressions DESC
    LIMIT 100

    โฆษณาพร้อมสถานะนโยบาย

    SELECT
      ad_group_ad.ad.id,
      ad_group_ad.ad.name,
      ad_group_ad.ad.type,
      ad_group_ad.status,
      ad_group_ad.policy_summary.approval_status,
      ad_group.id,
      ad_group.name,
      campaign.id,
      campaign.name
    FROM ad_group_ad

    Conversion Actions

    SELECT
      conversion_action.id,
      conversion_action.name,
      conversion_action.status,
      conversion_action.type,
      conversion_action.category,
      conversion_action.include_in_conversions_metric,
      conversion_action.counting_type
    FROM conversion_action

    รูปแบบการเรียกใช้ใน Python

    def gaql_query(client, customer_id, query):
        gs = client.get_service('GoogleAdsService')
        results = []
        for batch in gs.search_stream(customer_id=customer_id, query=query):
            for row in batch.results:
                results.append(row)
        return results

    ขั้นตอนที่ 6: การดำเนินการเขียนด้วย `validate_only`

    API v22 ต้องการ request objects ไม่ใช่ keyword arguments ทุก mutation service (CampaignService, AdGroupService, AdGroupCriterionService, CampaignBudgetService) มีรูปแบบเดียวกัน:

    from google.protobuf import field_mask_pb2
    
    req = client.get_type('MutateCampaignsRequest')
    req.customer_id = '1305475941'
    req.validate_only = True
    op = client.get_type('CampaignOperation')
    op.create.name = 'Campaign Name'
    op.create.status = client.enums.CampaignStatusEnum.PAUSED
    op.create.advertising_channel_type = client.enums.AdvertisingChannelTypeEnum.SEARCH
    op.create.campaign_budget = 'customers/1305475941/campaignBudgets/123456789'
    op.create.manual_cpc.enhanced_cpc_enabled = False
    req.operations.append(op)  # .append(), not .add()
    client.get_service('CampaignService').mutate_campaigns(request=req)

    ความแตกต่างสำคัญจาก API เวอร์ชันเก่า:

  • validate_only เป็นฟิลด์บน request object ไม่ใช่ keyword argument ของเมธอด mutate
  • Operations ถูกเพิ่มผ่าน req.operations.append(op) ไม่ใช่ req.operations.add(op)
  • Resource paths เป็นสตริงที่ระบุอย่างชัดเจน ('customers/1305475941/campaigns/22479990461') ไม่ใช่ค่าที่ส่งคืนจาก helper method
  • กระบวนการ Mutation สามขั้นตอน

    เพื่อความปลอดภัยในการใช้งานจริง (production) การทำ mutation จะผ่านสามขั้นตอน:

    ขั้นตอนที่ 1 — validate_only=True: API ตรวจสอบโครงสร้างคำขอ, ฟิลด์ที่จำเป็น และการอ้างอิงทรัพยากร ยังไม่มีการสร้างออบเจ็กต์ ควรทำขั้นตอนนี้ก่อนทุก mutation

    ขั้นตอนที่ 2 — สร้างแบบหยุดชั่วคราว (Paused Creation): ตั้งค่า validate_only=False และสร้างออบเจ็กต์ด้วย status=PAUSED ตรวจสอบผลลัพธ์ด้วยคำถามอ่านก่อนดำเนินการต่อ

    ขั้นตอนที่ 3 — เปิดใช้งานจริง (Live Enable): การเรียก API แยกต่างหากที่อัปเดตเฉพาะฟิลด์ status เป็น ENABLED การดำเนินการนี้ควรต้องได้รับการอนุมัติอย่างชัดเจน ไม่ควรรวมอยู่ในการสร้าง

    # Gate 3: enable a previously created paused campaign
    req = client.get_type('MutateCampaignsRequest')
    req.customer_id = '1305475941'
    req.validate_only = False
    op = client.get_type('CampaignOperation')
    op.update.resource_name = 'customers/1305475941/campaigns/22479990461'
    op.update.status = client.enums.CampaignStatusEnum.ENABLED
    op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['status']))
    req.operations.append(op)
    client.get_service('CampaignService').mutate_campaigns(request=req)

    การอัปเดตงบประมาณ

    req = client.get_type('MutateCampaignBudgetsRequest')
    req.customer_id = '1305475941'
    req.validate_only = True
    op = client.get_type('CampaignBudgetOperation')
    op.update.resource_name = 'customers/1305475941/campaignBudgets/123456789'
    op.update.amount_micros = 1_000_000  # $1.00 per day
    op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['amount_micros']))
    req.operations.append(op)
    client.get_service('CampaignBudgetService').mutate_campaign_budgets(request=req)

    การอัปเดตราคาเสนอของกลุ่มโฆษณา

    req = client.get_type('MutateAdGroupsRequest')
    req.customer_id = '1305475941'
    req.validate_only = True
    op = client.get_type('AdGroupOperation')
    op.update.resource_name = 'customers/1305475941/adGroups/165827073530'
    op.update.cpc_bid_micros = 250_000  # $0.25
    op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['cpc_bid_micros']))
    req.operations.append(op)
    client.get_service('AdGroupService').mutate_ad_groups(request=req)

    การสร้างคีย์เวิร์ด

    req = client.get_type('MutateAdGroupCriteriaRequest')
    req.customer_id = '1305475941'
    req.validate_only = True
    op = client.get_type('AdGroupCriterionOperation')
    op.create.ad_group = 'customers/1305475941/adGroups/165827073530'
    op.create.status = client.enums.AdGroupCriterionStatusEnum.PAUSED
    op.create.keyword.text = 'example keyword'
    op.create.keyword.match_type = client.enums.KeywordMatchTypeEnum.EXACT
    req.operations.append(op)
    client.get_service('AdGroupCriterionService').mutate_ad_group_criteria(request=req)

    การจัดการข้อผิดพลาด

    from google.ads.googleads.errors import GoogleAdsException
    
    try:
        response = service.mutate_campaigns(request=req)
    except GoogleAdsException as ex:
        for error in ex.failure.errors:
            print(f'{error.error_code}: {error.message}')

    รหัสข้อผิดพลาดที่พบบ่อยและความหมาย:

    Error Codeสาเหตุ
    `RESOURCE_NOT_FOUND`Test Access token กับบัญชีจริง (เป็นไปตามที่คาด) หรือทรัพยากรไม่มีอยู่จริง
    `REQUIRED`ขาดฟิลด์บังคับ (เช่น bidding strategy ในการสร้างแคมเปญ)
    `UNRECOGNIZED_FIELD`ฟิลด์จาก API เวอร์ชันอื่นหรือชื่อฟิลด์ไม่ถูกต้อง
    `INVALID_ARGUMENT`ค่าฟิลด์ไม่ผ่านการตรวจสอบ (เช่น งบประมาณติดลบ)
    `PERMISSION_DENIED`ผู้ใช้ OAuth ไม่มีสิทธิ์เข้าถึงบัญชีเป้าหมาย

    ระดับการเข้าถึง API

    การเข้าถึง Google Ads API เป็นแบบลำดับชั้น ไม่ใช่แบบมีหรือไม่มี:

    ระดับการออกให้อ่าน (Production)เขียน (Production)เขียน (Test Accounts)จำนวน Operations ต่อวัน
    **Test Access**ทันทีจาก MCC API Center15,000
    **Basic Access**การสมัคร + การตรวจสอบ Compliance15,000
    **Standard Access**เกณฑ์การใช้จ่าย + การตรวจสอบไม่จำกัด

    Test Access เพียงพอสำหรับการพัฒนา: การยืนยันตัวตน, คำถาม GAQL, การทดสอบ validate_only และการอ่าน/เขียนเต็มรูปแบบกับบัญชีทดสอบ Google Ads การก้าวไปสู่ Basic Access ถูกควบคุมโดยการตรวจสอบ compliance ไม่ใช่โดยการใช้จ่าย

    Standard Access ยกเลิกขีดจำกัดจำนวน operations ต่อวัน ซึ่งต้องมีประวัติการใช้จ่ายที่จัดการผ่าน token หรือการสมัครแยกต่างหาก

    บัญชีทดสอบ

    บัญชีทดสอบเป็นบัญชี Google Ads ฟรีที่ไม่มีการเรียกเก็บเงิน สามารถรับ mutation ใด ๆ ได้ วิธีการสร้าง: ใน MCC ไปที่ Accounts → + → Create new account → Test account เชื่อมโยงกับ MCC และใช้เป็น customer_id เป้าหมายในระหว่างการพัฒนาด้วย Test-Access

    `validate_only` ในแต่ละระดับการเข้าถึง

    validate_only=True ทำงานได้ในทุกระดับการเข้าถึง แต่ Test Access ยังคงปฏิเสธ mutation แบบ validate_only กับบัญชีจริงด้วย RESOURCE_NOT_FOUND นี่ไม่ใช่ข้อจำกัดของ validate_only — แต่เป็นการควบคุมการเข้าถึงแบบเดียวกับที่ใช้กับการดำเนินการเขียนทั้งหมด ไม่ว่าจะมี flag validate_only หรือไม่ก็ตาม

    Conversion Tracking: การอ่านผ่าน API vs. สถานะการทำงานจริง

    UI ของ Google Ads อาจแสดง "Set up conversion tracking" เป็นคำแนะนำแม้ว่าจะมี conversion action อยู่แล้วและเปิดใช้งานอยู่ API สามารถยืนยันการมีอยู่ของ conversion action (ประเภท WEBPAGE, หมวดหมู่ PURCHASE, สถานะ ENABLED, include_in_conversions_metric: true) แต่นี่เป็นเพียงการพิสูจน์ว่าออบเจ็กต์ conversion action มีอยู่จริง ไม่ได้พิสูจน์ว่าเว็บไซต์ส่ง event AW-.../label ที่สอดคล้องกัน, แท็ก Google ถูกโหลด, หรือมีสัญญาณ conversion ถูกรับแล้ว

    เมื่อตรวจสอบ conversion tracking ให้แยกการตรวจสอบผ่าน API (metadata ของ conversion action) ออกจากการตรวจสอบผ่านเบราว์เซอร์ (แท็บ network, การโหลดแท็ก, การส่ง event) API เป็นแหล่งความจริงสำหรับการกำหนดค่า ส่วนเบราว์เซอร์เป็นแหล่งความจริงสำหรับการทำงาน

    รูปแบบสำหรับ การระบุรายได้ฝั่ง backend นำมาใช้ที่นี่: หาก event conversion ฝั่ง client ไม่น่าเชื่อถือ ให้วางแผนสำหรับการอัปโหลด conversion แบบ server-side หรือ offline ผ่าน ConversionUploadService ของ Google Ads API เป็นทางสำรอง

    การกำหนดเวอร์ชัน API

    ไลบรารี google-ads สำหรับ Python มาพร้อมกับ API หลายเวอร์ชัน ณ เดือนมิถุนายน 2026 มี v19 ถึง v22 ให้ใช้งาน แต่ละเวอร์ชันเพิ่ม, เลิกใช้งาน (deprecate) หรือลบฟิลด์ GAQL และเมธอดของ service

    กฎสำหรับการเลือกเวอร์ชัน:

  • ระบุเวอร์ชันอย่างชัดเจนใน load_from_storage(version='v22') ค่าเริ่มต้นอาจล้าสมัย
  • ตรวจสอบ Google Ads API release notes สำหรับการเลิกใช้งานฟิลด์ก่อนอัปเกรด
  • เมธอด search_stream มีให้ใช้งานตั้งแต่ v6+ และเป็นเส้นทางการอ่านที่แนะนำ
  • Protobuf-plus (use_proto_plus: true) จำเป็นสำหรับ v12+
  • รูปแบบ request-object สำหรับ mutations (mutate_campaigns(request=req)) แทนที่รูปแบบ keyword-argument ใน v17+
  • ความปลอดภัยในเครื่อง

    ไฟล์ข้อมูลรับรองทั้งหมดต้องอยู่นอก version control:

    ~/.hermes/
      google-ads.yaml          # 0600 — dev token, OAuth client, refresh token
      google_ads_token.json    # 0600 — OAuth tokens, adwords scope
      google_client_secret.json # 0600 — OAuth client ID + secret

    สำหรับ repository ที่ทำงาน ให้เพิ่ม .gitignore:

    google-ads.yaml
    *_token*.json
    *_secret*.json

    สามารถ commit ไฟล์แม่แบบที่มีค่าตัวแทนเพื่อบันทึกโครงสร้างที่คาดหวัง:

    # google-ads.yaml.template — commit this, fill locally
    developer_token: INSERT_DEV_TOKEN
    client_id: INSERT_CLIENT_ID
    client_secret: INSERT_CLIENT_SECRET
    refresh_token: INSERT_REFRESH_TOKEN
    login_customer_id: INSERT_MCC_ID
    use_proto_plus: true

    ฟิลด์ที่จำเป็นสำหรับการดำเนินการทั่วไป

    การดำเนินการฟิลด์ที่จำเป็น
    Create Campaign (Search)`name`, `status`, `advertising_channel_type`, `campaign_budget`, `manual_cpc` หรือ bidding strategy
    Create Ad Group (Search)`name`, `status`, `type_`, `cpc_bid_micros`, `campaign`
    Create Keyword`ad_group`, `status`, `keyword.text`, `keyword.match_type`
    Update Campaign Status`resource_name`, `status`, `update_mask` (paths: `['status']`)
    Update Budget`resource_name`, `amount_micros`, `update_mask` (paths: `['amount_micros']`)

    การขาดฟิลด์ที่จำเป็นจะส่งคืน REQUIRED พร้อมชื่อฟิลด์ การขาด update_mask ในการดำเนินการอัปเดตจะถูกเพิกเฉยอย่างเงียบ ๆ — ฟิลด์นั้นจะไม่ถูกอัปเดตและไม่มีข้อผิดพลาดส่งกลับ

    สคริปต์ทดสอบฉบับสมบูรณ์

    สคริปต์เดียวที่อ่านประเภทเอนทิตีทั้งหมดและทำการทดสอบการเขียนแบบ validate_only:

    # google_ads_api_test.py — read all entities + validate_only write tests
    import warnings
    warnings.filterwarnings('ignore')
    from google.ads.googleads.client import GoogleAdsClient
    from google.ads.googleads.errors import GoogleAdsException
    from google.protobuf import field_mask_pb2
    
    CFG = '/path/to/google-ads.yaml'
    CID = '1305475941'
    c = GoogleAdsClient.load_from_storage(CFG, version='v22')
    gs = c.get_service('GoogleAdsService')
    
    def gaql(query, label):
        print(f'\n=== {label} ===')
        n = 0
        for batch in gs.search_stream(customer_id=CID, query=query):
            for row in batch.results:
                n += 1
        print(f'{n} rows')
    
    # Read all entities
    gaql("SELECT customer.id, customer.descriptive_name FROM customer WHERE customer.id = ...", "CUSTOMER")
    gaql("SELECT campaign.id, campaign.name, campaign.status, ...  FROM campaign", "CAMPAIGNS")
    gaql("SELECT campaign_budget.id, campaign_budget.name, ...  FROM campaign_budget", "BUDGETS")
    gaql("SELECT ad_group.id, ad_group.name, ...  FROM ad_group", "AD GROUPS")
    gaql("SELECT ad_group_criterion.keyword.text, ...  FROM keyword_view WHERE ...", "KEYWORDS")
    gaql("SELECT ad_group_ad.ad.id, ...  FROM ad_group_ad", "ADS")
    gaql("SELECT conversion_action.id, ...  FROM conversion_action", "CONVERSIONS")
    
    # Write tests
    def test_write(name, fn):
        print(f'\n--- {name} ---')
        try:
            fn()
            print('PASS')
        except GoogleAdsException as e:
            for err in e.failure.errors:
                print(f'{err.error_code}: {err.message}')
    
    def test_create_campaign():
        req = c.get_type('MutateCampaignsRequest')
        req.customer_id = CID
        req.validate_only = True
        op = c.get_type('CampaignOperation')
        op.create.name = 'TEST_CAMPAIGN'
        op.create.status = c.enums.CampaignStatusEnum.PAUSED
        op.create.advertising_channel_type = c.enums.AdvertisingChannelTypeEnum.SEARCH
        op.create.campaign_budget = f'customers/{CID}/campaignBudgets/123456789'
        op.create.manual_cpc.enhanced_cpc_enabled = False
        req.operations.append(op)
        c.get_service('CampaignService').mutate_campaigns(request=req)
    
    test_write('Create Campaign (validate_only)', test_create_campaign)
    print('\nDone.')

    เวอร์ชันที่ทำงานได้เต็มรูปแบบอยู่ที่ Google Ads API operations skill ใน advertising operations repository

    เอกสารอ้างอิง

  • Google Ads API Documentation
  • google-ads Python Library
  • GAQL Reference
  • OAuth 2.0 for Desktop Apps
  • Building a Project-Specific AI Assistant via Telegram — รูปแบบ OAuth เดียวกันที่ใช้กับ Google scope อื่น
  • Reference Architecture for a Thread-Based AI Operations Layer — โมเดลปฏิบัติการที่ API automation เชื่อมต่อเข้าไป
  • Solo Operations at Scale: Managing Dozens of Projects with a Small Team — เหตุผลที่ API automation แทนที่การทำงานผ่าน UI ด้วยตนเองในระดับขนาดใหญ่
  • บทความที่เกี่ยวข้อง