Connect Google Ads Scripts with external APIs, CRM systems, data warehouses, and enterprise data sources for unified marketing automation.
// Salesforce CRM integration for lead quality optimization
function optimizeCampaignsWithCRMData() {
Logger.log("=== CRM-Driven Campaign Optimization ===");
// Fetch lead quality data from CRM API
const crmData = fetchSalesforceLeadData();
Logger.log(`Retrieved data for ${Object.keys(crmData).length} campaigns from CRM`);
const campaigns = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.withCondition('Cost > 500 DURING LAST_30_DAYS')
.get();
let optimized = 0;
while (campaigns.hasNext()) {
const campaign = campaigns.next();
const campaignName = campaign.getName();
// Match campaign with CRM data
const leadData = crmData[campaignName];
if (!leadData) {
Logger.log(`No CRM data found for: ${campaignName}`);
continue;
}
// Calculate lead quality metrics
const leadScore = calculateLeadQuality(leadData);
const conversionRate = leadData.closedWon / leadData.totalLeads;
const avgDealValue = leadData.totalRevenue / leadData.closedWon;
Logger.log(`${campaignName}: Score=${leadScore}, CVR=${(conversionRate*100).toFixed(1)}%, AOV=€${avgDealValue.toFixed(0)}`);
// Adjust budget based on lead quality
const currentBudget = campaign.getBudget();
let budgetMultiplier = 1.0;
if (leadScore >= 80 && conversionRate > 0.15) {
budgetMultiplier = 1.3; // Increase high-quality campaigns
} else if (leadScore >= 60 && conversionRate > 0.10) {
budgetMultiplier = 1.1; // Slight increase for good campaigns
} else if (leadScore < 40 || conversionRate < 0.05) {
budgetMultiplier = 0.7; // Decrease poor-quality campaigns
}
const newBudget = Math.round(currentBudget * budgetMultiplier);
if (newBudget !== currentBudget) {
campaign.setBudget(newBudget);
optimized++;
Logger.log(`Updated budget: €${currentBudget} → €${newBudget} (Quality: ${leadScore}/100)`);
// Update CRM with optimization status
updateSalesforceRecord(campaignName, {
lastOptimized: new Date().toISOString(),
budgetAdjustment: budgetMultiplier,
leadQualityScore: leadScore
});
}
}
Logger.log(`=== Optimization Complete: ${optimized} campaigns updated ===`);
}
function fetchSalesforceLeadData() {
const SF_API_ENDPOINT = PropertiesService.getScriptProperties().getProperty('SF_API_URL');
const SF_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty('SF_ACCESS_TOKEN');
const response = UrlFetchApp.fetch(SF_API_ENDPOINT + '/leads/campaign-summary', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + SF_ACCESS_TOKEN,
'Content-Type': 'application/json'
}
});
if (response.getResponseCode() !== 200) {
throw new Error(`CRM API Error: ${response.getResponseCode()}`);
}
return JSON.parse(response.getContentText());
}
function calculateLeadQuality(leadData) {
// Multi-factor lead quality scoring
const conversionScore = Math.min(leadData.closedWon / leadData.totalLeads * 100, 40);
const valueScore = Math.min(leadData.totalRevenue / leadData.totalLeads / 100, 30);
const velocityScore = Math.min(30 / leadData.avgSalesCycle * 20, 20);
const engagementScore = Math.min(leadData.emailOpens / leadData.totalLeads * 10, 10);
return Math.round(conversionScore + valueScore + velocityScore + engagementScore);
}This example shows how to integrate Salesforce CRM data to optimize Google Ads campaigns based on actual lead quality and conversion outcomes.
// BigQuery data warehouse integration for advanced attribution
function optimizeWithDataWarehouseInsights() {
Logger.log("=== Data Warehouse Attribution Analysis ===");
// Query advanced attribution data from BigQuery
const attributionData = queryBigQueryAttribution();
const campaigns = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.get();
while (campaigns.hasNext()) {
const campaign = campaigns.next();
const campaignId = campaign.getId();
const attribution = attributionData[campaignId];
if (!attribution) continue;
// Calculate true ROAS including offline conversions
const trueROAS = (attribution.onlineRevenue + attribution.offlineRevenue) / attribution.adSpend;
const crossChannelContribution = attribution.assistedConversions / attribution.totalConversions;
Logger.log(`${campaign.getName()}: True ROAS=${trueROAS.toFixed(2)}, Cross-channel=${(crossChannelContribution*100).toFixed(1)}%`);
// Adjust bidding strategy based on complete attribution picture
const keywords = campaign.keywords()
.withCondition('Status = ENABLED')
.get();
while (keywords.hasNext()) {
const keyword = keywords.next();
const currentBid = keyword.getMaxCpc();
// Increase bids for keywords with high cross-channel value
let bidMultiplier = 1.0;
if (trueROAS > 4.0 && crossChannelContribution > 0.3) {
bidMultiplier = 1.25; // Strong cross-channel performance
} else if (trueROAS > 3.0 && crossChannelContribution > 0.2) {
bidMultiplier = 1.1; // Good assisted conversions
} else if (trueROAS < 2.0) {
bidMultiplier = 0.85; // Underperforming even with attribution
}
if (bidMultiplier !== 1.0) {
const newBid = currentBid * bidMultiplier;
keyword.setMaxCpc(newBid);
Logger.log(`Bid adjusted: ${keyword.getText()} €${currentBid.toFixed(2)} → €${newBid.toFixed(2)}`);
}
}
}
}
function queryBigQueryAttribution() {
const BQ_PROJECT_ID = PropertiesService.getScriptProperties().getProperty('BQ_PROJECT_ID');
const BQ_DATASET = PropertiesService.getScriptProperties().getProperty('BQ_DATASET');
// BigQuery SQL for cross-channel attribution analysis
const query = `
SELECT
campaign_id,
SUM(online_revenue) as onlineRevenue,
SUM(offline_revenue) as offlineRevenue,
SUM(ad_spend) as adSpend,
SUM(assisted_conversions) as assistedConversions,
SUM(total_conversions) as totalConversions
FROM `${BQ_PROJECT_ID}.${BQ_DATASET}.attribution_model`
WHERE date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
GROUP BY campaign_id
`;
// Execute BigQuery request (simplified - actual implementation would use BigQuery API)
const response = UrlFetchApp.fetch(`https://bigquery.googleapis.com/bigquery/v2/projects/${BQ_PROJECT_ID}/queries`, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + getGCPAccessToken(),
'Content-Type': 'application/json'
},
payload: JSON.stringify({
query: query,
useLegacySql: false
})
});
const result = JSON.parse(response.getContentText());
// Transform results into lookup object
const attributionMap = {};
result.rows.forEach(row => {
attributionMap[row.f[0].v] = {
onlineRevenue: parseFloat(row.f[1].v),
offlineRevenue: parseFloat(row.f[2].v),
adSpend: parseFloat(row.f[3].v),
assistedConversions: parseInt(row.f[4].v),
totalConversions: parseInt(row.f[5].v)
};
});
return attributionMap;
}