Come caricare dati grezzi da Google Ads su Google BigQuery
Pubblicato: 2022-04-12Analizzando l'efficacia delle campagne pubblicitarie di Google Ads in Google Analytics, potresti riscontrare limitazioni di campionamento, aggregazione di dati o altre interfacce di sistema. Fortunatamente, questo problema è facilmente risolvibile caricando i dati grezzi dal tuo servizio pubblicitario su Google BigQuery.
In questo articolo imparerai come caricare dati grezzi dal tuo account Google Ads su BigQuery e identificare tutti i tag UTM per le campagne con etichettatura automatica.
Hai bisogno di OWOX BI per collegare le informazioni sulla campagna all'attività degli utenti sul sito. Iscriviti per una demo e ti descriveremo in dettaglio tutte le sfide che puoi risolvere con OWOX BI.
Sommario
- Perché hai bisogno di dati grezzi da Google Ads
- Due modi per caricare dati grezzi da Google Ads in BigQuery
- Come configurare il caricamento tramite Trasferimento dati
- Come impostare il caricamento utilizzando Ads Script
- Come collegare il download dei dati da Google Ads a OWOX BI
- Consigli utili
Scopri il vero valore delle campagne
Importa automaticamente i dati sui costi in Google Analytics da tutti i tuoi servizi pubblicitari. Confronta i costi della campagna, il CPC e il ritorno sulla spesa pubblicitaria in un unico rapporto.

Perché hai bisogno di dati grezzi da Google Ads
I dati grezzi di Google Ads ti permetteranno di analizzare le campagne pubblicitarie con precisione fino a ogni parola chiave. Caricando i dati su BigQuery, puoi:
- Crea report dettagliati come desideri senza essere limitato dalle restrizioni GA.
- Determina l'efficacia delle campagne pubblicitarie a livello di sessione e utente.
- Calcola ROI, ROAS, CRR per regione, tipo di utente (nuovo o restituito), dispositivo e qualsiasi altro parametro.
- Gestisci le tue tariffe in modo efficace e crea elenchi per il remarketing.
- Combina i dati di Google Ads, Google Analytics e CRM per valutare l'efficacia delle campagne in base al margine e alla riscattabilità dei tuoi articoli.
- Addestra il tuo modello ML per una pianificazione più accurata.
Per capire quali campagne, annunci e parole chiave portano gli utenti al tuo sito, devi combinare i dati di Google Ads e Analytics in BigQuery. Puoi farlo usando lo streaming OWOX BI.
Lo streaming di queste informazioni invia dati sul comportamento degli utenti non campionati sul tuo sito a GBQ. Gli hit vengono trasmessi in tempo reale, quindi le sessioni vengono formate sulla base di questi hit.
Le informazioni sulla sorgente di traffico di OWOX BI sono tratte dal markup pubblicitario dei tag UTM. I tag sono manuali e automatici.
Supponiamo che tu abbia contrassegnato l'annuncio manualmente e che tu abbia ottenuto questo URL:
https://example.com/?utm_source=facebook&utm_medium=cpc&utm_campaign=utm_tags
In questo caso, dopo aver collegato OWOX BI, avrai a disposizione i dati di origine, canale e campagna nella tabella GBQ:
- trafficSource.source — google
- trafficSource.medium — cpc
- trafficSource.campaign — utm_tags
Ulteriori informazioni su come creare correttamente i tag UTM.
Se hai abilitato il markup automatico nel servizio pubblicitario, a ciascuno dei tuoi annunci viene assegnato un parametro gclid speciale. Viene aggiunto all'URL della pagina di destinazione quando l'utente fa clic sull'annuncio.
Esempio di tale collegamento:
http://www.example.com/?gclid=TeSter-123
Se utilizzi un markup automatico, non puoi ottenere sorgente, mezzo o campagna da gclid senza dati grezzi: questi campi saranno vuoti nelle tabelle BigQuery raccolte da OWOX BI.
Cosa puoi fare in questo caso e come puoi ottenere il nome delle campagne e altri parametri, avendo solo il gclid? Configura il caricamento automatico da Google Ads a GBQ.
Nota: se l'annuncio non è contrassegnato affatto, OWOX BI assegnerà il collegamento come segue:
- per sorgenti non Google come traffico referral (es. facebook/referral)
- per la sorgente Google come traffico diretto (diretto/nessuno)
Se c'è molto traffico diretto/nessuno nei tuoi rapporti, potresti non avere il filtro bot abilitato o potresti avere un numero elevato di annunci senza tag.
Due modi per caricare dati grezzi da Google Ads in BigQuery
Utilizziamo e consigliamo due metodi per caricare dati grezzi da Google Ads: Data Transfer Connector e Ads Script.
Il modo in cui scegli dipende dai tuoi obiettivi e dal tuo budget.
Funzionalità di trasferimento dati
- Integrazione nativa con GBQ.
- Scarica i dati storici per qualsiasi periodo senza restrizioni.
- Gratuito.
Funzionalità di Google Ads Script
- Libero.
- Non puoi caricare dati storici. Vengono scaricate solo le informazioni del giorno precedente.
- Richiede di più se desideri impostare il caricamento da un numero elevato di account. Dovrai apportare manualmente le modifiche agli script per ciascun account. Allo stesso tempo, c'è un alto rischio di commettere un errore.
Cosa ti serve per le impostazioni
Progetti attivi e account in:
- Piattaforma Google Cloud (GCP)
- Google BigQuery (GBQ)
- OWOX BI
- Annunci Google
Accesso:
- Proprietario in GCP
- Amministratore in GBQ
- Modifica in OWOX BI. Importante: solo l'utente che ha creato la pipeline di streaming di Google Analytics → Google BigQuery può attivare il download da Google Ads.
- Leggere in Google Ads
Come concedere i diritti di accesso in GBQ
Apri la console GCP e seleziona IAM e amministratore — Gestisci risorsa dal menu laterale. Quindi seleziona il progetto e fai clic su Aggiungi membro. Inserisci l'email dell'utente, seleziona il ruolo di amministratore BigQuery e salva le modifiche.

Come configurare il caricamento tramite Trasferimento dati
Passaggio 1. Crea un progetto in Google Cloud Platform
Se hai già un progetto in GCP, salta questo passaggio. In caso contrario, apri la console GCP e seleziona IAM e amministratore — Gestisci risorsa dal menu laterale. Fare clic sul pulsante Crea progetto. Quindi inserisci il nome del progetto, specifica l'organizzazione e fai clic su Crea:

Assicurati di abilitare la fatturazione. Per fare ciò, apri la scheda Fatturazione - Gestione account nel menu laterale, seleziona il progetto e collega Account di fatturazione:

Successivamente, completa tutti i campi inserendo i tuoi contatti e i dettagli della carta di pagamento. Se questo è il tuo primo progetto in GCP, riceverai $ 300 che possono essere utilizzati per 12 mesi. I progetti con 1-2 account Google Ads e fino a 100.000 utenti unici al mese ne avranno abbastanza per un anno. Quando si esaurisce questo limite, non è necessario restituire il denaro. Per un ulteriore utilizzo, è sufficiente ricaricare il saldo sulla carta che hai collegato al progetto.
Passaggio 2. Attiva API BigQuery
Dopo aver creato un progetto, devi attivare l'API BigQuery. Per fare ciò, vai su API e servizi - Dashboard dal menu laterale di GCP, seleziona il progetto e fai clic su Abilita API e servizi:

Nella libreria API, cerca "BigQuery API" e fai clic su Abilita:

Per utilizzare l'API, fai clic su Crea credenziali:

Dall'elenco a discesa, scegli l'API BigQuery e fai clic su Di quali credenziali ho bisogno?

Crea il nome dell'account di servizio e specifica il livello di accesso del ruolo BigQuery. Seleziona il tipo di chiave JSON e fai clic su Continua:

Passaggio 3. Attiva l'API di trasferimento dati
Successivamente, devi attivare il servizio dati in BigQuery. Per fare ciò, apri GBQ e seleziona Trasferimenti dal menu laterale a sinistra. Quindi abilita l'API BigQuery Data Transfer:

Passaggio 4. Preparare il set di dati in GBQ
In BigQuery, seleziona il progetto e fai clic sul pulsante Crea set di dati a destra. Completa tutti i campi obbligatori per il nuovo set di dati (nome, posizione, conservazione):

Passaggio 5. Imposta il trasferimento dei dati da Google Ads
Fare clic sulla scheda Trasferimenti nel menu laterale, quindi fare clic su Crea trasferimento. Quindi seleziona Google Ads (ex AdWords) come origine e inserisci il nome del caricamento, ad esempio Trasferimento dati.
In Opzioni di pianificazione, puoi lasciare l'impostazione predefinita su Inizia ora o impostare la data e l'ora in cui desideri iniziare il download. Nel campo Ripeti, seleziona la frequenza di caricamento: giornaliera, settimanale, mensile su richiesta, ecc.

Quindi devi specificare il set di dati GBQ in cui caricare i rapporti da Google Ads. Inserisci l'ID cliente (questo è l'ID del tuo account Google Ads o ID Centro clienti) e fai clic su Aggiungi. Puoi visualizzare l'ID cliente nel tuo account Google Ads nell'angolo in alto a destra, accanto alla tua email.

Quindi devi autorizzare l'account Gmail che stai utilizzando. Il giorno successivo, le informazioni appariranno nel set di dati specificato durante la configurazione del trasferimento.
Di conseguenza, riceverai una grande quantità di dati grezzi in GBQ con cui puoi lavorare: tabelle per campagne, segmenti di pubblico, tabelle comuni (personalizzate), parole chiave e conversioni. Ad esempio, se desideri creare un dashboard personalizzato, puoi estrarre dati non aggregati da queste tabelle.
Come impostare il caricamento utilizzando Ads Script
Apri il tuo account Google Ads, fai clic su Strumenti e impostazioni nell'angolo in alto a destra, seleziona Azioni collettive - Script e fai clic sul simbolo Più:

Quindi, nell'angolo in alto a destra, fai clic sul pulsante API avanzate, seleziona BigQuery e salva le modifiche:

Assicurati di registrarti con l'account con cui hai eseguito l'accesso a Google Ads con:

Copia lo script qui sotto. Nelle righe BIGQUERY_PROJECT_ID, BIGQUERY_DATASET_ID e Your email, sostituisci i valori con le tue informazioni: nome del progetto, set di dati GBQ ed email. Incolla il testo dello script nell'editor di testo.
/** * @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'); }
Prima di eseguire lo script, assicurati di fare clic sul pulsante Anteprima nell'angolo in basso a destra per controllare il risultato. Se sono presenti errori, il sistema ti avviserà e indicherà in quale riga si è verificato, come in questa schermata:


Se non ci sono errori, fare clic sul pulsante Esegui:

Di conseguenza, riceverai un nuovo report CLICK_PERFORMANCE_REPORT nel tuo GBQ che sarà disponibile il giorno successivo:

Ricorda che quando utilizzi Data Transfer, ottieni una grande quantità di dati grezzi non aggregati. Con Ads Script, avrai solo informazioni su determinati campi.
I seguenti campi di questo caricamento sono inclusi nelle tabelle BI OWOX relative alla sessione:
- Gclid
- ID campagna
- Nome della campagna
- IDGruppo di annunci
- Nomegruppo di annunci
- CriterioId
- CriteriParametri
- KeywordMatchType
Come collegare il download dei dati da Google Ads a OWOX BI
Ora devi combinare le informazioni di Google Ads con i dati del sito per capire con quali campagne gli utenti hanno raggiunto il tuo sito. Le tabelle che ottieni in BigQuery, come Data Transfer, non hanno un parametro Client ID. Puoi determinare quale cliente ha fatto clic sugli annunci solo collegando i dati gclid ai dati del flusso BI OWOX.
Se non hai ancora la pipeline di streaming di Google Analytics → Google BigQuery in OWOX BI, leggi le istruzioni su come crearla.
Quindi vai al tuo progetto OWOX BI e apri questa pipeline. Fare clic sulla scheda Impostazioni e, in Raccolta dati sessione, fare clic su Modifica impostazioni:

Utilizza il dispositivo di scorrimento per abilitare la raccolta dei dati per le campagne con etichetta automatica di Google Ads e fai clic su Modifica impostazioni:

Seleziona il tipo di markup AutoLabel, specifica come caricare gli script Data Transfer o Ads in BigQuery. Specifica il progetto e il set di dati da cui verranno scaricati i dati di Google Ads e salva le impostazioni:

Consigli utili
Suggerimento 1. Con Trasferimento dati, puoi caricare dati storici da Google Ads a GBQ. Allo stesso tempo, non ci sono restrizioni sul periodo totale di carico (né per un anno, né per tre), ma con dati per soli 180 giorni alla volta.
Puoi attivare il caricamento e specificare il periodo utilizzando il pulsante Pianifica riempimento nella scheda Trasferimenti selezionando il trasferimento che desideri:

Suggerimento 2. Se desideri controllare il numero di account Google Ads addebitati da GCP, devi determinare il numero di ExternalCustomerID nella tabella Customer utilizzando la query:
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
È possibile modificare le date nella query.
Suggerimento 3. Puoi accedere tu stesso ai dati caricati utilizzando le query SQL. Ecco, ad esempio, una query per determinare l'efficacia delle campagne dalle tabelle "Campaign" e "CampaignBasicStats" derivate da Data Transfer:
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
PS Se hai bisogno di aiuto con il caricamento e l'unione dei dati in Google BigQuery, siamo pronti ad aiutarti. Iscriviti per una demo e discuteremo i dettagli.