Google Ads'den Google BigQuery'ye ham veriler nasıl yüklenir?
Yayınlanan: 2022-04-12Google Ads reklam kampanyalarının Google Analytics'teki etkinliğini analiz ederken, örnekleme, veri toplama veya diğer sistem arayüzü kısıtlamalarıyla karşılaşabilirsiniz. Neyse ki, bu sorun, reklam hizmetinizden Google BigQuery'ye ham veriler yükleyerek kolayca çözülür.
Bu makalede, Google Ads hesabınızdaki ham verileri BigQuery'ye nasıl yükleyeceğinizi ve otomatik etiketlenen kampanyalar için tüm UTM etiketlerini nasıl tanımlayacağınızı öğreneceksiniz.
Kampanya bilgilerini sitedeki kullanıcı etkinliğine bağlamak için OWOX BI'a ihtiyacınız var. Bir demo için kaydolun ve OWOX BI ile çözebileceğiniz tüm zorlukları detaylandıralım.
İçindekiler
- Google Ads'den neden ham verilere ihtiyacınız var?
- Google Ads'den BigQuery'ye ham veri yüklemenin iki yolu
- Veri Aktarımı kullanılarak yükleme nasıl yapılandırılır
- Reklam Komut Dosyası kullanılarak yükleme nasıl kurulur?
- Google Ads'den OWOX BI'ye veri indirme bağlantısı nasıl yapılır?
- Faydalı ipuçları
Kampanyaların gerçek değerini öğrenin
Tüm reklamcılık hizmetlerinizden maliyet verilerini otomatik olarak Google Analytics'e aktarın. Tek bir raporda kampanya maliyetlerini, TBM'yi ve ROAS'ı karşılaştırın.

Google Ads'den neden ham verilere ihtiyacınız var?
Google Ads'den elde edilen ham veriler, reklam kampanyalarını her bir anahtar kelimeye kadar doğrulukla analiz etmenize olanak tanır. BigQuery'ye veri yükleyerek şunları yapabilirsiniz:
- GA kısıtlamalarıyla sınırlandırılmadan istediğiniz kadar ayrıntılı raporlar oluşturun.
- Oturum ve kullanıcı düzeyinde reklam kampanyalarının etkinliğini belirleyin.
- Bölgeye, kullanıcı tipine (yeni veya iade edilen), cihaza ve diğer parametrelere göre ROI, ROAS, CRR'yi hesaplayın.
- Ücretlerinizi etkin bir şekilde yönetin ve yeniden pazarlama listeleri oluşturun.
- Öğelerinizin marjına ve kullanılabilirliğine dayalı olarak kampanyaların etkinliğini değerlendirmek için Google Ads, Google Analytics ve CRM'den gelen verileri birleştirin.
- Daha doğru planlama için ML modelinizi eğitin.
Hangi kampanyaların, reklamların ve anahtar kelimelerin kullanıcıları sitenize getirdiğini anlamak için Google Ads ve Analytics'ten gelen verileri BigQuery'de birleştirmeniz gerekir. Bunu OWOX BI akışını kullanarak yapabilirsiniz.
Bu bilgilerin akışı, sitenizdeki örneklenmemiş kullanıcı davranışı verilerini GBQ'ya gönderir. Hit'ler gerçek zamanlı olarak iletilir, daha sonra bu isabetlere göre oturumlar oluşturulur.
OWOX BI trafik kaynağı bilgileri, UTM etiketleri reklam işaretlemesinden alınır. Etiketler manuel ve otomatiktir.
Reklamı manuel olarak işaretlediğinizi ve şu URL'yi aldığınızı varsayalım:
https://example.com/?utm_source=facebook&utm_medium=cpc&utm_campaign=utm_tags
Bu durumda, OWOX BI'yi bağladıktan sonra GBQ tablosunda kaynak, kanal ve kampanya verileriniz olacaktır:
- trafikSource.source — google
- trafikSource.medium — cpc
- trafikSource.campaign — utm_tags
UTM etiketlerinin nasıl doğru şekilde oluşturulacağı hakkında daha fazlasını okuyun.
Reklam hizmetinde otomatik işaretlemeyi etkinleştirdiyseniz, reklamlarınızın her birine özel bir gclid parametresi atanır. Kullanıcı duyuruyu tıkladığında açılış sayfası URL'sine eklenir.
Böyle bir bağlantı örneği:
http://www.example.com/?gclid=TeSter-123
Otomatik işaretleme kullanıyorsanız, ham veriler olmadan gclid'den kaynak, aracı veya kampanya alamazsınız - bu alanlar OWOX BI'nin topladığı BigQuery tablolarında boş olacaktır.
Böyle bir durumda ne yapabilirsiniz ve yalnızca gclid'e sahip olan kampanyaların ve diğer parametrelerin adını nasıl alabilirsiniz? Google Ads'den GBQ'ya otomatik yüklemeyi yapılandırın.
Not: Duyuru hiç işaretlenmemişse, OWOX BI bağlantıyı aşağıdaki gibi atayacaktır:
- yönlendirme trafiği olarak Google dışı kaynaklar için (ör. facebook/yönlendirme)
- doğrudan trafik olarak Google kaynağı için (doğrudan/yok)
Raporlarınızda çok sayıda doğrudan trafik varsa/yoksa, bot filtrelemeyi etkinleştirmemiş olabilirsiniz veya çok sayıda etiketlenmemiş reklamınız olabilir.
Google Ads'den BigQuery'ye ham veri yüklemenin iki yolu
Google Ads'den ham verileri yüklemek için iki yöntem kullanır ve öneririz: Veri Aktarımı Bağlayıcı ve Reklam Komut Dosyası.
Hangi yolu seçeceğiniz, hedeflerinize ve bütçenize bağlıdır.
Veri Aktarımı özellikleri
- GBQ ile yerel entegrasyon.
- Kısıtlama olmaksızın herhangi bir dönem için geçmiş verileri indirin.
- ücretsiz.
Google Ads Komut Dosyası özellikleri
- Özgür.
- Geçmiş verileri yükleyemezsiniz. Yalnızca bir önceki günün bilgileri indirilir.
- Çok sayıda hesaptan yüklemeyi ayarlamak istiyorsanız daha fazlasını gerektirir. Her hesap için komut dosyası değişikliklerini manuel olarak yapmanız gerekecektir. Aynı zamanda, hata yapma riski yüksektir.
Ayarlar için gerekenler
Aktif projeler ve hesaplar:
- Google Bulut Platformu (GCP)
- Google BigQuery (GBQ)
- OWOX BI
- Google Reklamları
Giriş:
- GCP'de sahip
- GBQ'da yönetici
- OWOX BI'da düzenleme. Önemli: Yalnızca Google Analytics → Google BigQuery akış ardışık düzenini oluşturan kullanıcı Google Ads'den indirmeyi açabilir.
- Google Ads'de Okuma
GBQ'da erişim hakları nasıl verilir
GCP konsolunu açın ve yan menüden IAM ve yönetici - Kaynağı Yönet'i seçin. Ardından projeyi seçin ve Üye Ekle'ye tıklayın. Kullanıcının e-postasını girin, BigQuery Yöneticisi rolünü seçin ve değişikliklerinizi kaydedin.

Veri Aktarımı kullanılarak yükleme nasıl yapılandırılır
1. Adım. Google Cloud Platform'da bir proje oluşturun
GCP'de zaten bir projeniz varsa bu adımı atlayın. Değilse, GCP konsolunu açın ve yan menüden IAM ve yönetici — Kaynağı Yönet'i seçin. Proje Oluştur düğmesini tıklayın. Ardından proje adını girin, organizasyonu belirtin ve Oluştur'a tıklayın:

Faturalandırmayı etkinleştirdiğinizden emin olun. Bunu yapmak için, yan menüdeki Faturalama - Hesap Yönetimi sekmesini açın, projeyi seçin ve Faturalandırma Hesabı bağlantısını bağlayın:

Ardından, kişilerinizi ve ödeme kartı bilgilerinizi girerek tüm alanları doldurun. Bu, GCP'deki ilk projenizse, 12 ay boyunca kullanılabilecek 300 ABD doları alacaksınız. 1-2 Google Ads hesabı ve ayda 100.000'e kadar benzersiz kullanıcısı olan projeler bir yıl için yeterli olacaktır. Bu limiti tükettiğinizde parayı iade etmenize gerek yoktur. Daha fazla kullanım için, projeye bağladığınız karttaki bakiyeyi yeniden doldurmanız yeterlidir.
2. Adım. API BigQuery'yi açın
Bir proje oluşturduktan sonra BigQuery API'sini etkinleştirmeniz gerekir. Bunu yapmak için GCP yan menüsünden API'ler ve Hizmetler - Gösterge Tablosu'na gidin, projeyi seçin ve API'leri ve Hizmetleri Etkinleştir'i tıklayın:

API kitaplığında "BigQuery API"yi arayın ve Etkinleştir'e tıklayın:

API'yi kullanmak için Kimlik Bilgileri Oluştur'a tıklayın:

Açılır listeden BigQuery API'sini seçin ve Hangi kimlik bilgilerine ihtiyacım var? seçeneğini tıklayın.

Hizmet hesabının adını oluşturun ve BigQuery Rolü erişim düzeyini belirtin. JSON anahtarının türünü seçin ve Devam'ı tıklayın:

3. Adım. Veri Aktarımı API'sini Etkinleştirin
Ardından, BigQuery'de veri hizmetini etkinleştirmeniz gerekir. Bunu yapmak için GBQ'yu açın ve soldaki yan menüden Transferler'i seçin. Ardından BigQuery Veri Aktarımı API'sini etkinleştirin:

Adım 4. GBQ cinsinden veri setini hazırlayın
BigQuery'de projeyi seçin ve sağdaki Veri Kümesi Oluştur düğmesini tıklayın. Yeni veri kümesi için gerekli tüm alanları doldurun (ad, konum, saklama):

5. Adım. Google Ads'den veri aktarımını ayarlayın
Yan menüdeki Transferler sekmesine tıklayın ve ardından Transfer Oluştur'a tıklayın. Ardından kaynak olarak Google Ads'ü (eski adıyla AdWords) seçin ve yüklemenin adını (örneğin, Veri Aktarımı) girin.
Zamanlama seçenekleri altında, varsayılanı Şimdi başla olarak bırakabilir veya indirmeye başlamak istediğiniz tarih ve saati ayarlayabilirsiniz. Tekrarlar alanında, ne sıklıkta yükleneceğini seçin: günlük, haftalık, isteğe bağlı aylık vb.

Ardından, raporları Google Ads'den yüklemek için GBQ veri kümesini belirtmeniz gerekir. Müşteri Kimliğini girin (bu, Google Ads hesabınızın veya MM Kimliğinizin kimliğidir) ve Ekle'yi tıklayın. Google Ads hesabınızda, sağ üst köşede, e-postanızın yanında Müşteri Kimliğini görüntüleyebilirsiniz.

Ardından, kullandığınız Gmail hesabını yetkilendirmeniz gerekir. Ertesi gün, aktarımı kurduğunuzda belirttiğiniz veri kümesinde bilgiler görünecektir.
Sonuç olarak, çalışabileceğiniz GBQ cinsinden büyük miktarda ham veri alacaksınız: kampanyalara göre tablolar, kitleler, ortak (özel) tablolar, anahtar kelimeler ve dönüşümler. Örneğin, özel bir pano oluşturmak istiyorsanız, bu tablolardan toplu olmayan verileri çekebilirsiniz.
Reklam Komut Dosyası kullanılarak yükleme nasıl kurulur?
Google Ads hesabınızı açın, sağ üst köşedeki Araçlar ve Ayarlar'ı tıklayın, Toplu İşlemler - Komut Dosyaları'nı seçin ve Artı simgesini tıklayın:

Ardından, sağ üst köşede Gelişmiş API'ler düğmesini tıklayın, BigQuery'yi seçin ve değişikliklerinizi kaydedin:

Google Ads'de oturum açtığınız hesapla kaydolduğunuzdan emin olun:

Aşağıdaki komut dosyasını kopyalayın. BIGQUERY_PROJECT_ID, BIGQUERY_DATASET_ID ve Your email satırlarında, değerleri kendi bilgilerinizle değiştirin: proje adı, GBQ veri seti ve e-posta. Komut dosyası metnini metin düzenleyiciye yapıştırın.
/** * @name Export Data to BigQuery * * @overview The Export Data to BigQuery script sets up a BigQuery * dataset and tables, downloads a report from AdWords and then * loads the report to BigQuery. * * @author AdWords Scripts Team [[email protected]] * * @version 1.3 */ var CONFIG = { BIGQUERY_PROJECT_ID: 'BQ project name', BIGQUERY_DATASET_ID: AdWordsApp.currentAccount().getCustomerId().replace(/-/g, '_'), // Truncate existing data, otherwise will append. TRUNCATE_EXISTING_DATASET: false, TRUNCATE_EXISTING_TABLES: true, // Lists of reports and fields to retrieve from AdWords. REPORTS: [], RECIPIENT_EMAILS: [ 'Your email' ] }; var report = { NAME: 'CLICK_PERFORMANCE_REPORT', //https://developers.google.com/adwords/api/docs/appendix/reports/click-performance-report CONDITIONS: '', FIELDS: {'AccountDescriptiveName': 'STRING', 'AdFormat': 'STRING', 'AdGroupId': 'STRING', 'AdGroupName': 'STRING', 'AoiCountryCriteriaId': 'STRING', 'CampaignId': 'STRING', 'CampaignLocationTargetId': 'STRING', 'CampaignName': 'STRING', 'CampaignStatus': 'STRING', 'Clicks': 'INTEGER', 'ClickType': 'STRING', 'CreativeId': 'STRING', 'CriteriaId': 'STRING', 'CriteriaParameters': 'STRING', 'Date': 'DATE', 'Device': 'STRING', 'ExternalCustomerId': 'STRING', 'GclId': 'STRING', 'KeywordMatchType': 'STRING', 'LopCountryCriteriaId': 'STRING', 'Page': 'INTEGER' }, DATE_RANGE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, ""), DATE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "") }; //Regular export CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //One-time historical export //for(var i=2;i<91;i++){ // report.DATE_RANGE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // report.DATE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //} /** * Main method */ function main() { createDataset(); for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; createTable(reportConfig); } var jobIds = processReports(); waitTillJobsComplete(jobIds); sendEmail(jobIds); } /** * Creates a new dataset. * * If a dataset with the same id already exists and the truncate flag * is set, will truncate the old dataset. If the truncate flag is not * set, then will not create a new dataset. */ function createDataset() { if (datasetExists()) { if (CONFIG.TRUNCATE_EXISTING_DATASET) { BigQuery.Datasets.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, {'deleteContents' : true}); Logger.log('Truncated dataset.'); } else { Logger.log('Dataset %s already exists. Will not recreate.', CONFIG.BIGQUERY_DATASET_ID); return; } } // Create new dataset. var dataSet = BigQuery.newDataset(); dataSet.friendlyName = CONFIG.BIGQUERY_DATASET_ID; dataSet.datasetReference = BigQuery.newDatasetReference(); dataSet.datasetReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; dataSet.datasetReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; dataSet = BigQuery.Datasets.insert(dataSet, CONFIG.BIGQUERY_PROJECT_ID); Logger.log('Created dataset with id %s.', dataSet.id); } /** * Checks if dataset already exists in project. * * @return {boolean} Returns true if dataset already exists. */ function datasetExists() { // Get a list of all datasets in project. var datasets = BigQuery.Datasets.list(CONFIG.BIGQUERY_PROJECT_ID); var datasetExists = false; // Iterate through each dataset and check for an id match. if (datasets.datasets != null) { for (var i = 0; i < datasets.datasets.length; i++) { var dataset = datasets.datasets[i]; if (dataset.datasetReference.datasetId == CONFIG.BIGQUERY_DATASET_ID) { datasetExists = true; break; } } } return datasetExists; } /** * Creates a new table. * * If a table with the same id already exists and the truncate flag * is set, will truncate the old table. If the truncate flag is not * set, then will not create a new table. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. */ function createTable(reportConfig) { var tableName = reportConfig.NAME+reportConfig.DATE; if (tableExists(tableName)) { if (CONFIG.TRUNCATE_EXISTING_TABLES) { BigQuery.Tables.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, tableName); Logger.log('Truncated table %s.', tableName); } else { Logger.log('Table %s already exists. Will not recreate.', tableName); return; } } // Create new table. var table = BigQuery.newTable(); var schema = BigQuery.newTableSchema(); var bigQueryFields = []; // Add each field to table schema. var fieldNames = Object.keys(reportConfig.FIELDS); for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var bigQueryFieldSchema = BigQuery.newTableFieldSchema(); bigQueryFieldSchema.description = fieldName; bigQueryFieldSchema.name = fieldName; bigQueryFieldSchema.type = reportConfig.FIELDS[fieldName]; bigQueryFields.push(bigQueryFieldSchema); } schema.fields = bigQueryFields; table.schema = schema; table.friendlyName = tableName; table.tableReference = BigQuery.newTableReference(); table.tableReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; table.tableReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; table.tableReference.tableId = tableName; table = BigQuery.Tables.insert(table, CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); Logger.log('Created table with id %s.', table.id); } /** * Checks if table already exists in dataset. * * @param {string} tableId The table id to check existence. * * @return {boolean} Returns true if table already exists. */ function tableExists(tableId) { // Get a list of all tables in the dataset. var tables = BigQuery.Tables.list(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); var tableExists = false; // Iterate through each table and check for an id match. if (tables.tables != null) { for (var i = 0; i < tables.tables.length; i++) { var table = tables.tables[i]; if (table.tableReference.tableId == tableId) { tableExists = true; break; } } } return tableExists; } /** * Process all configured reports * * Iterates through each report to: retrieve AdWords data, * backup data to Drive (if configured), load data to BigQuery. * * @return {Array.<string>} jobIds The list of all job ids. */ function processReports() { var jobIds = []; // Iterate over each report type. for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; Logger.log('Running report %s', reportConfig.NAME); // Get data as csv var csvData = retrieveAdwordsReport(reportConfig); //Logger.log(csvData); // Convert to Blob format. var blobData = Utilities.newBlob(csvData, 'application/octet-stream'); // Load data var jobId = loadDataToBigquery(reportConfig, blobData); jobIds.push(jobId); } return jobIds; } /** * Retrieves AdWords data as csv and formats any fields * to BigQuery expected format. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * * @return {string} csvData Report in csv format. */ function retrieveAdwordsReport(reportConfig) { var fieldNames = Object.keys(reportConfig.FIELDS); var query = 'SELECT ' + fieldNames.join(', ') + ' FROM ' + reportConfig.NAME + '' + reportConfig.CONDITIONS + ' DURING ' + reportConfig.DATE_RANGE; Logger.log(query); var report = AdWordsApp.report(query); var rows = report.rows(); var csvRows = []; // Header row csvRows.push(fieldNames.join(',')); // Iterate over each row. while (rows.hasNext()) { var row = rows.next(); var csvRow = []; for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var fieldValue = row[fieldName].toString(); var fieldType = reportConfig.FIELDS[fieldName]; // Strip off % and perform any other formatting here. if (fieldType == 'FLOAT' || fieldType == 'INTEGER') { if (fieldValue.charAt(fieldValue.length - 1) == '%') { fieldValue = fieldValue.substring(0, fieldValue.length - 1); } fieldValue = fieldValue.replace(/,/g,''); if (fieldValue == '--' || fieldValue == 'Unspecified') { fieldValue = '' } } // Add double quotes to any string values. if (fieldType == 'STRING') { if (fieldValue == '--') { fieldValue = '' } fieldValue = fieldValue.replace(/"/g, '""'); fieldValue = '"' + fieldValue + '"' } csvRow.push(fieldValue); } csvRows.push(csvRow.join(',')); } Logger.log('Downloaded ' + reportConfig.NAME + ' with ' + csvRows.length + ' rows.'); return csvRows.join('\n'); } /** * Creates a BigQuery insertJob to load csv data. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * @param {Blob} data Csv report data as an 'application/octet-stream' blob. * * @return {string} jobId The job id for upload. */ function loadDataToBigquery(reportConfig, data) { // Create the data upload job. var job = { configuration: { load: { destinationTable: { projectId: CONFIG.BIGQUERY_PROJECT_ID, datasetId: CONFIG.BIGQUERY_DATASET_ID, tableId: reportConfig.NAME + reportConfig.DATE }, skipLeadingRows: 1 } } }; var insertJob = BigQuery.Jobs.insert(job, CONFIG.BIGQUERY_PROJECT_ID, data); Logger.log('Load job started for %s. Check on the status of it here: ' + 'https://bigquery.cloud.google.com/jobs/%s', reportConfig.NAME, CONFIG.BIGQUERY_PROJECT_ID); return insertJob.jobReference.jobId; } /** * Polls until all jobs are 'DONE'. * * @param {Array.<string>} jobIds The list of all job ids. */ function waitTillJobsComplete(jobIds) { var complete = false; var remainingJobs = jobIds; while (!complete) { if (AdWordsApp.getExecutionInfo().getRemainingTime() < 5){ Logger.log('Script is about to timeout, jobs ' + remainingJobs.join(',') + ' are still incomplete.'); } remainingJobs = getIncompleteJobs(remainingJobs); if (remainingJobs.length == 0) { complete = true; } if (!complete) { Logger.log(remainingJobs.length + ' jobs still being processed.'); // Wait 5 seconds before checking status again. Utilities.sleep(5000); } } Logger.log('All jobs processed.'); } /** * Iterates through jobs and returns the ids for those jobs * that are not 'DONE'. * * @param {Array.<string>} jobIds The list of job ids. * * @return {Array.<string>} remainingJobIds The list of remaining job ids. */ function getIncompleteJobs(jobIds) { var remainingJobIds = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var getJob = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); if (getJob.status.state != 'DONE') { remainingJobIds.push(jobId); } } return remainingJobIds; } /** * Sends a notification email that jobs have completed loading. * * @param {Array.<string>} jobIds The list of all job ids. */ function sendEmail(jobIds) { var html = []; html.push( '<html>', '<body>', '<table width=800 cellpadding=0 border=0 cellspacing=0>', '<tr>', '<td colspan=2 align=right>', "<div style='font: italic normal 10pt Times New Roman, serif; " + "margin: 0; color: #666; padding-right: 5px;'>" + 'Powered by AdWords Scripts</div>', '</td>', '</tr>', "<tr bgcolor='#3c78d8'>", '<td width=500>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>Adwords data load to " + "Bigquery report</div>", '</td>', '<td align=right>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>", AdWordsApp.currentAccount().getCustomerId(), '</tr>', '</table>', '<table width=800 cellpadding=0 border=1 cellspacing=0>', "<tr bgcolor='#ddd'>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>Report</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>JobId</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>Rows</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>State</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>ErrorResult</td>", '</tr>', createTableRows(jobIds), '</table>', '</body>', '</html>'); MailApp.sendEmail(CONFIG.RECIPIENT_EMAILS.join(','), 'Adwords data load to Bigquery Complete', '', {htmlBody: html.join('\n')}); } /** * Creates table rows for email report. * * @param {Array.<string>} jobIds The list of all job ids. */ function createTableRows(jobIds) { var html = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var job = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); var errorResult = '' if (job.status.errorResult) { errorResult = job.status.errorResult; } html.push('<tr>', "<td style='padding: 0px 10px'>" + job.configuration.load.destinationTable.tableId + '</td>', "<td style='padding: 0px 10px'>" + jobId + '</td>', "<td style='padding: 0px 10px'>" + job.statistics.load?job.statistics.load.outputRows:0 + '</td>', "<td style='padding: 0px 10px'>" + job.status.state + '</td>', "<td style='padding: 0px 10px'>" + errorResult + '</td>', '</tr>'); } return html.join('\n'); }
/** * @name Export Data to BigQuery * * @overview The Export Data to BigQuery script sets up a BigQuery * dataset and tables, downloads a report from AdWords and then * loads the report to BigQuery. * * @author AdWords Scripts Team [[email protected]] * * @version 1.3 */ var CONFIG = { BIGQUERY_PROJECT_ID: 'BQ project name', BIGQUERY_DATASET_ID: AdWordsApp.currentAccount().getCustomerId().replace(/-/g, '_'), // Truncate existing data, otherwise will append. TRUNCATE_EXISTING_DATASET: false, TRUNCATE_EXISTING_TABLES: true, // Lists of reports and fields to retrieve from AdWords. REPORTS: [], RECIPIENT_EMAILS: [ 'Your email' ] }; var report = { NAME: 'CLICK_PERFORMANCE_REPORT', //https://developers.google.com/adwords/api/docs/appendix/reports/click-performance-report CONDITIONS: '', FIELDS: {'AccountDescriptiveName': 'STRING', 'AdFormat': 'STRING', 'AdGroupId': 'STRING', 'AdGroupName': 'STRING', 'AoiCountryCriteriaId': 'STRING', 'CampaignId': 'STRING', 'CampaignLocationTargetId': 'STRING', 'CampaignName': 'STRING', 'CampaignStatus': 'STRING', 'Clicks': 'INTEGER', 'ClickType': 'STRING', 'CreativeId': 'STRING', 'CriteriaId': 'STRING', 'CriteriaParameters': 'STRING', 'Date': 'DATE', 'Device': 'STRING', 'ExternalCustomerId': 'STRING', 'GclId': 'STRING', 'KeywordMatchType': 'STRING', 'LopCountryCriteriaId': 'STRING', 'Page': 'INTEGER' }, DATE_RANGE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, ""), DATE: new Date(new Date().setDate(new Date().getDate()-1)).toISOString().slice(0, 10).replace(/-/g, "") }; //Regular export CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //One-time historical export //for(var i=2;i<91;i++){ // report.DATE_RANGE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, "")+','+new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // report.DATE = new Date(new Date().setDate(new Date().getDate()-i)).toISOString().slice(0, 10).replace(/-/g, ""); // CONFIG.REPORTS.push(JSON.parse(JSON.stringify(report))); //} /** * Main method */ function main() { createDataset(); for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; createTable(reportConfig); } var jobIds = processReports(); waitTillJobsComplete(jobIds); sendEmail(jobIds); } /** * Creates a new dataset. * * If a dataset with the same id already exists and the truncate flag * is set, will truncate the old dataset. If the truncate flag is not * set, then will not create a new dataset. */ function createDataset() { if (datasetExists()) { if (CONFIG.TRUNCATE_EXISTING_DATASET) { BigQuery.Datasets.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, {'deleteContents' : true}); Logger.log('Truncated dataset.'); } else { Logger.log('Dataset %s already exists. Will not recreate.', CONFIG.BIGQUERY_DATASET_ID); return; } } // Create new dataset. var dataSet = BigQuery.newDataset(); dataSet.friendlyName = CONFIG.BIGQUERY_DATASET_ID; dataSet.datasetReference = BigQuery.newDatasetReference(); dataSet.datasetReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; dataSet.datasetReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; dataSet = BigQuery.Datasets.insert(dataSet, CONFIG.BIGQUERY_PROJECT_ID); Logger.log('Created dataset with id %s.', dataSet.id); } /** * Checks if dataset already exists in project. * * @return {boolean} Returns true if dataset already exists. */ function datasetExists() { // Get a list of all datasets in project. var datasets = BigQuery.Datasets.list(CONFIG.BIGQUERY_PROJECT_ID); var datasetExists = false; // Iterate through each dataset and check for an id match. if (datasets.datasets != null) { for (var i = 0; i < datasets.datasets.length; i++) { var dataset = datasets.datasets[i]; if (dataset.datasetReference.datasetId == CONFIG.BIGQUERY_DATASET_ID) { datasetExists = true; break; } } } return datasetExists; } /** * Creates a new table. * * If a table with the same id already exists and the truncate flag * is set, will truncate the old table. If the truncate flag is not * set, then will not create a new table. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. */ function createTable(reportConfig) { var tableName = reportConfig.NAME+reportConfig.DATE; if (tableExists(tableName)) { if (CONFIG.TRUNCATE_EXISTING_TABLES) { BigQuery.Tables.remove(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID, tableName); Logger.log('Truncated table %s.', tableName); } else { Logger.log('Table %s already exists. Will not recreate.', tableName); return; } } // Create new table. var table = BigQuery.newTable(); var schema = BigQuery.newTableSchema(); var bigQueryFields = []; // Add each field to table schema. var fieldNames = Object.keys(reportConfig.FIELDS); for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var bigQueryFieldSchema = BigQuery.newTableFieldSchema(); bigQueryFieldSchema.description = fieldName; bigQueryFieldSchema.name = fieldName; bigQueryFieldSchema.type = reportConfig.FIELDS[fieldName]; bigQueryFields.push(bigQueryFieldSchema); } schema.fields = bigQueryFields; table.schema = schema; table.friendlyName = tableName; table.tableReference = BigQuery.newTableReference(); table.tableReference.datasetId = CONFIG.BIGQUERY_DATASET_ID; table.tableReference.projectId = CONFIG.BIGQUERY_PROJECT_ID; table.tableReference.tableId = tableName; table = BigQuery.Tables.insert(table, CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); Logger.log('Created table with id %s.', table.id); } /** * Checks if table already exists in dataset. * * @param {string} tableId The table id to check existence. * * @return {boolean} Returns true if table already exists. */ function tableExists(tableId) { // Get a list of all tables in the dataset. var tables = BigQuery.Tables.list(CONFIG.BIGQUERY_PROJECT_ID, CONFIG.BIGQUERY_DATASET_ID); var tableExists = false; // Iterate through each table and check for an id match. if (tables.tables != null) { for (var i = 0; i < tables.tables.length; i++) { var table = tables.tables[i]; if (table.tableReference.tableId == tableId) { tableExists = true; break; } } } return tableExists; } /** * Process all configured reports * * Iterates through each report to: retrieve AdWords data, * backup data to Drive (if configured), load data to BigQuery. * * @return {Array.<string>} jobIds The list of all job ids. */ function processReports() { var jobIds = []; // Iterate over each report type. for (var i = 0; i < CONFIG.REPORTS.length; i++) { var reportConfig = CONFIG.REPORTS[i]; Logger.log('Running report %s', reportConfig.NAME); // Get data as csv var csvData = retrieveAdwordsReport(reportConfig); //Logger.log(csvData); // Convert to Blob format. var blobData = Utilities.newBlob(csvData, 'application/octet-stream'); // Load data var jobId = loadDataToBigquery(reportConfig, blobData); jobIds.push(jobId); } return jobIds; } /** * Retrieves AdWords data as csv and formats any fields * to BigQuery expected format. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * * @return {string} csvData Report in csv format. */ function retrieveAdwordsReport(reportConfig) { var fieldNames = Object.keys(reportConfig.FIELDS); var query = 'SELECT ' + fieldNames.join(', ') + ' FROM ' + reportConfig.NAME + '' + reportConfig.CONDITIONS + ' DURING ' + reportConfig.DATE_RANGE; Logger.log(query); var report = AdWordsApp.report(query); var rows = report.rows(); var csvRows = []; // Header row csvRows.push(fieldNames.join(',')); // Iterate over each row. while (rows.hasNext()) { var row = rows.next(); var csvRow = []; for (var i = 0; i < fieldNames.length; i++) { var fieldName = fieldNames[i]; var fieldValue = row[fieldName].toString(); var fieldType = reportConfig.FIELDS[fieldName]; // Strip off % and perform any other formatting here. if (fieldType == 'FLOAT' || fieldType == 'INTEGER') { if (fieldValue.charAt(fieldValue.length - 1) == '%') { fieldValue = fieldValue.substring(0, fieldValue.length - 1); } fieldValue = fieldValue.replace(/,/g,''); if (fieldValue == '--' || fieldValue == 'Unspecified') { fieldValue = '' } } // Add double quotes to any string values. if (fieldType == 'STRING') { if (fieldValue == '--') { fieldValue = '' } fieldValue = fieldValue.replace(/"/g, '""'); fieldValue = '"' + fieldValue + '"' } csvRow.push(fieldValue); } csvRows.push(csvRow.join(',')); } Logger.log('Downloaded ' + reportConfig.NAME + ' with ' + csvRows.length + ' rows.'); return csvRows.join('\n'); } /** * Creates a BigQuery insertJob to load csv data. * * @param {Object} reportConfig Report configuration including report name, * conditions, and fields. * @param {Blob} data Csv report data as an 'application/octet-stream' blob. * * @return {string} jobId The job id for upload. */ function loadDataToBigquery(reportConfig, data) { // Create the data upload job. var job = { configuration: { load: { destinationTable: { projectId: CONFIG.BIGQUERY_PROJECT_ID, datasetId: CONFIG.BIGQUERY_DATASET_ID, tableId: reportConfig.NAME + reportConfig.DATE }, skipLeadingRows: 1 } } }; var insertJob = BigQuery.Jobs.insert(job, CONFIG.BIGQUERY_PROJECT_ID, data); Logger.log('Load job started for %s. Check on the status of it here: ' + 'https://bigquery.cloud.google.com/jobs/%s', reportConfig.NAME, CONFIG.BIGQUERY_PROJECT_ID); return insertJob.jobReference.jobId; } /** * Polls until all jobs are 'DONE'. * * @param {Array.<string>} jobIds The list of all job ids. */ function waitTillJobsComplete(jobIds) { var complete = false; var remainingJobs = jobIds; while (!complete) { if (AdWordsApp.getExecutionInfo().getRemainingTime() < 5){ Logger.log('Script is about to timeout, jobs ' + remainingJobs.join(',') + ' are still incomplete.'); } remainingJobs = getIncompleteJobs(remainingJobs); if (remainingJobs.length == 0) { complete = true; } if (!complete) { Logger.log(remainingJobs.length + ' jobs still being processed.'); // Wait 5 seconds before checking status again. Utilities.sleep(5000); } } Logger.log('All jobs processed.'); } /** * Iterates through jobs and returns the ids for those jobs * that are not 'DONE'. * * @param {Array.<string>} jobIds The list of job ids. * * @return {Array.<string>} remainingJobIds The list of remaining job ids. */ function getIncompleteJobs(jobIds) { var remainingJobIds = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var getJob = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); if (getJob.status.state != 'DONE') { remainingJobIds.push(jobId); } } return remainingJobIds; } /** * Sends a notification email that jobs have completed loading. * * @param {Array.<string>} jobIds The list of all job ids. */ function sendEmail(jobIds) { var html = []; html.push( '<html>', '<body>', '<table width=800 cellpadding=0 border=0 cellspacing=0>', '<tr>', '<td colspan=2 align=right>', "<div style='font: italic normal 10pt Times New Roman, serif; " + "margin: 0; color: #666; padding-right: 5px;'>" + 'Powered by AdWords Scripts</div>', '</td>', '</tr>', "<tr bgcolor='#3c78d8'>", '<td width=500>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>Adwords data load to " + "Bigquery report</div>", '</td>', '<td align=right>', "<div style='font: normal 18pt verdana, sans-serif; " + "padding: 3px 10px; color: white'>", AdWordsApp.currentAccount().getCustomerId(), '</tr>', '</table>', '<table width=800 cellpadding=0 border=1 cellspacing=0>', "<tr bgcolor='#ddd'>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>Report</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5px 5px; background-color: #ddd; ' + "text-align: left'>JobId</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>Rows</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>State</td>", "<td style='font: 12pt verdana, sans-serif; " + 'padding: 5px 0px 5x 5px; background-color: #ddd; ' + "text-align: left'>ErrorResult</td>", '</tr>', createTableRows(jobIds), '</table>', '</body>', '</html>'); MailApp.sendEmail(CONFIG.RECIPIENT_EMAILS.join(','), 'Adwords data load to Bigquery Complete', '', {htmlBody: html.join('\n')}); } /** * Creates table rows for email report. * * @param {Array.<string>} jobIds The list of all job ids. */ function createTableRows(jobIds) { var html = []; for (var i = 0; i < jobIds.length; i++) { var jobId = jobIds[i]; var job = BigQuery.Jobs.get(CONFIG.BIGQUERY_PROJECT_ID, jobId); var errorResult = '' if (job.status.errorResult) { errorResult = job.status.errorResult; } html.push('<tr>', "<td style='padding: 0px 10px'>" + job.configuration.load.destinationTable.tableId + '</td>', "<td style='padding: 0px 10px'>" + jobId + '</td>', "<td style='padding: 0px 10px'>" + job.statistics.load?job.statistics.load.outputRows:0 + '</td>', "<td style='padding: 0px 10px'>" + job.status.state + '</td>', "<td style='padding: 0px 10px'>" + errorResult + '</td>', '</tr>'); } return html.join('\n'); }
Komut dosyasını çalıştırmadan önce, sonucu kontrol etmek için sağ alt köşedeki Önizleme düğmesini tıkladığınızdan emin olun. Eğer hata varsa sistem sizi uyaracak ve bu ekran görüntüsündeki gibi hangi satırda oluştuğunu belirtecektir:


Hata yoksa Çalıştır düğmesine tıklayın:

Sonuç olarak, GBQ'nuzda ertesi gün kullanılabilecek yeni bir CLICK_PERFORMANCE_REPORT raporu alacaksınız:

Veri Aktarımı'nı kullandığınızda, büyük miktarda toplanmamış ham veri elde ettiğinizi hatırlayın. Ads Script ile sadece belirli alanlar hakkında bilgi sahibi olacaksınız.
Bu yüklemeden aşağıdaki alanlar, oturumla ilgili OWOX BI tablolarına dahil edilmiştir:
- GclId
- Kampanya Kimliği
- Kampanya ismi
- Reklam Grubu Kimliği
- Reklam GrubuAdı
- Ölçüt Kimliği
- CriteriaParameters
- Anahtar KelimeEşleme Türü
Google Ads'den OWOX BI'ye veri indirme bağlantısı nasıl yapılır?
Artık, kullanıcıların sitenize hangi kampanyalar aracılığıyla ulaştığını anlamak için Google Ads'den gelen bilgileri site verileriyle birleştirmeniz gerekiyor. Veri Aktarımı gibi BigQuery'de aldığınız tablolarda Müşteri Kimliği parametresi yoktur. Yalnızca gclid verilerini OWOX BI akış verilerine bağlayarak hangi müşterinin reklamları tıkladığını belirleyebilirsiniz.
OWOX BI'da henüz Google Analytics → Google BigQuery akış hattınız yoksa, nasıl oluşturulacağına ilişkin talimatları okuyun.
Ardından OWOX BI projenize gidin ve bu boru hattını açın. Ayarlar sekmesine tıklayın ve Oturum Verisi Toplama altında Ayarları Düzenle'ye tıklayın:

Google Ads otomatik etiketli kampanyalar için veri toplamayı etkinleştirmek için kaydırıcıyı kullanın ve Ayarları Değiştir'i tıklayın:

Otomatik Etiket işaretleme türünü seçin, Veri Aktarımı veya Reklam komut dosyalarının BigQuery'ye nasıl yükleneceğini belirtin. Google Ads verilerinin indirileceği projeyi ve veri kümesini belirtin ve ayarlarınızı kaydedin:

Faydalı ipuçları
İpucu 1. Veri Aktarımı ile, Google Ads'den GBQ'ya geçmiş verileri yükleyebilirsiniz. Aynı zamanda, toplam yükleme süresinde (bir yıl veya üç yıl için) herhangi bir kısıtlama yoktur, ancak bir seferde yalnızca 180 günlük verilerle.
Yüklemeyi etkinleştirebilir ve istediğiniz aktarımı seçerek Aktarımlar sekmesindeki Planla Doldur düğmesini kullanarak dönemi belirleyebilirsiniz:

İpucu 2. GCP'nin ücret alacağı Google Ads hesaplarının sayısını kontrol etmek istiyorsanız, aşağıdaki sorguyu kullanarak Müşteri tablosundaki HariciCustomerID sayısını belirlemeniz gerekir:
SELECT ExternalCustomerId FROM `project_name.dataset_name.Customer_*` WHERE _PARTITIONTIME >= "2020-01-01 00:00:00" AND _PARTITIONTIME < "2020-07-10 00:00:00" group by 1
SELECT ExternalCustomerId FROM `project_name.dataset_name.Customer_*` WHERE _PARTITIONTIME >= "2020-01-01 00:00:00" AND _PARTITIONTIME < "2020-07-10 00:00:00" group by 1
Sorgudaki tarihleri düzenleyebilirsiniz.
İpucu 3. Yüklenen verilere SQL sorgularını kullanarak kendiniz erişebilirsiniz. Örneğin, Veri Aktarımından türetilen "Campaign" ve "CampaignBasicStats" tablolarından kampanyaların etkinliğini belirlemeye yönelik bir sorgu:
SELECT {source language="sql"} c.ExternalCustomerId, c.CampaignName, c.CampaignStatus, SUM(cs.Impressions) AS Impressions, SUM(cs.Interactions) AS Interactions, {/source} (SUM(cs.Cost) / 1000000) AS Cost FROM `[DATASET].Campaign_[CUSTOMER_ID]` c LEFT JOIN {source language="sql"} {source language="sql"} `[DATASET].CampaignBasicStats_[CUSTOMER_ID]` cs ON (c.CampaignId = cs.CampaignId AND cs._DATA_DATE BETWEEN DATE_ADD(CURRENT_DATE(), INTERVAL -31 DAY) AND DATE_ADD(CURRENT_DATE(), INTERVAL -1 DAY)) WHERE c._DATA_DATE = c._LATEST_DATE GROUP BY 1, 2, 3 ORDER BY Impressions DESC
SELECT {source language="sql"} c.ExternalCustomerId, c.CampaignName, c.CampaignStatus, SUM(cs.Impressions) AS Impressions, SUM(cs.Interactions) AS Interactions, {/source} (SUM(cs.Cost) / 1000000) AS Cost FROM `[DATASET].Campaign_[CUSTOMER_ID]` c LEFT JOIN {source language="sql"} {source language="sql"} `[DATASET].CampaignBasicStats_[CUSTOMER_ID]` cs ON (c.CampaignId = cs.CampaignId AND cs._DATA_DATE BETWEEN DATE_ADD(CURRENT_DATE(), INTERVAL -31 DAY) AND DATE_ADD(CURRENT_DATE(), INTERVAL -1 DAY)) WHERE c._DATA_DATE = c._LATEST_DATE GROUP BY 1, 2, 3 ORDER BY Impressions DESC
Not: Google BigQuery'ye veri yükleme ve birleştirme konusunda yardıma ihtiyacınız varsa, size yardımcı olmaya hazırız. Bir demo için kaydolun - ayrıntıları tartışalım.