Script中心
MCC换链脚本
复制到 Google Ads Scripts 使用。
/**
* ABOS MCC Tracking Template updater.
*
* Copy this script into Google Ads Scripts at MCC level.
*/
var TRACKING_TEMPLATE_URL = 'https://lulutongagent.com/api/tracking-template';
var LOG_URL = 'https://lulutongagent.com/api/script-execution-logs';
var IMPORT_TOKEN = 'ABOS_GoogleAds_2026_x8K9mP2Q7';
var MAX_RETRIES = 3;
var SCRIPT_TYPE = 'mcc_tracking';
var LAST_FETCH_LOGGED = false;
function main() {
var accountIterator = AdsManagerApp.accounts()
.withCondition('CanManageClients = FALSE')
.get();
while (accountIterator.hasNext()) {
var account = accountIterator.next();
try {
AdsManagerApp.select(account);
updateCurrentAccountCampaigns();
} catch (e) {
Logger.log('Account failed: ' + account.getName() + ' | ' + e);
}
}
}
function updateCurrentAccountCampaigns() {
var account = AdsApp.currentAccount();
var accountName = account.getName();
var campaignIterator = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var campaignName = campaign.getName();
try {
LAST_FETCH_LOGGED = false;
var template = fetchTrackingTemplate(accountName, campaignName);
if (template) {
try {
campaign.urls().setTrackingTemplate(template);
Logger.log('Applied: ' + accountName + ' | ' + campaignName);
postExecutionLog(accountName, campaignName, 'apply_template', 'success', template, 'Applied', null);
} catch (applyError) {
Logger.log('Apply failed: ' + accountName + ' | ' + campaignName + ' | ' + applyError);
postExecutionLog(accountName, campaignName, 'apply_template', 'failed', template, null, String(applyError));
}
} else if (!LAST_FETCH_LOGGED) {
Logger.log('Skipped empty template: ' + accountName + ' | ' + campaignName);
postExecutionLog(accountName, campaignName, 'fetch_template', 'skipped', null, 'Empty template', null);
}
} catch (e) {
Logger.log('Campaign failed: ' + accountName + ' | ' + campaignName + ' | ' + e);
postExecutionLog(accountName, campaignName, 'fetch_template', 'failed', null, null, String(e));
}
}
}
function fetchTrackingTemplate(accountName, campaignName) {
var url = TRACKING_TEMPLATE_URL
+ '?google_account_name=' + encodeURIComponent(accountName)
+ '&campaign_name=' + encodeURIComponent(campaignName);
var response = fetchWithRetries(url);
var status = response.getResponseCode();
var body = response.getContentText();
if (status === 404) {
Logger.log('No template found: ' + accountName + ' | ' + campaignName);
postExecutionLog(accountName, campaignName, 'fetch_template', 'skipped', null, 'No template found', null);
LAST_FETCH_LOGGED = true;
return '';
}
if (status < 200 || status >= 300) {
Logger.log('Fetch failed: HTTP ' + status + ' | ' + body);
postExecutionLog(accountName, campaignName, 'fetch_template', 'failed', null, null, 'HTTP ' + status + ' | ' + body);
LAST_FETCH_LOGGED = true;
return '';
}
return String(body || '').trim();
}
function postExecutionLog(accountName, campaignName, action, status, template, message, errorMessage) {
try {
UrlFetchApp.fetch(LOG_URL, {
method: 'post',
contentType: 'application/json',
headers: {
'X-Import-Token': IMPORT_TOKEN
},
payload: JSON.stringify({
google_account_name: accountName,
campaign_name: campaignName,
script_type: SCRIPT_TYPE,
action: action,
status: status,
tracking_template: template,
message: message,
error_message: errorMessage,
executed_at: Utilities.formatDate(new Date(), AdsApp.currentAccount().getTimeZone(), 'yyyy-MM-dd HH:mm:ss')
}),
muteHttpExceptions: true
});
} catch (e) {
Logger.log('Log post failed: ' + e);
}
}
function fetchWithRetries(url) {
var lastResponse = null;
for (var i = 0; i < MAX_RETRIES; i++) {
try {
lastResponse = UrlFetchApp.fetch(url, {
method: 'get',
headers: {
'X-Import-Token': IMPORT_TOKEN
},
muteHttpExceptions: true
});
if (lastResponse.getResponseCode() < 500) {
return lastResponse;
}
} catch (e) {
Logger.log('Fetch attempt failed: ' + (i + 1) + ' | ' + e);
}
Utilities.sleep(1000 * (i + 1));
}
return lastResponse;
}
单账号换链脚本
复制到 Google Ads Scripts 使用。
/**
* ABOS single-account Tracking Template updater.
*
* Copy this script into Google Ads Scripts at account level.
*/
var TRACKING_TEMPLATE_URL = 'https://lulutongagent.com/api/tracking-template';
var LOG_URL = 'https://lulutongagent.com/api/script-execution-logs';
var IMPORT_TOKEN = 'ABOS_GoogleAds_2026_x8K9mP2Q7';
var MAX_RETRIES = 3;
var SCRIPT_TYPE = 'single_tracking';
var LAST_FETCH_LOGGED = false;
function main() {
var account = AdsApp.currentAccount();
var accountName = account.getName();
var campaignIterator = AdsApp.campaigns()
.withCondition('Status = ENABLED')
.get();
while (campaignIterator.hasNext()) {
var campaign = campaignIterator.next();
var campaignName = campaign.getName();
try {
LAST_FETCH_LOGGED = false;
var template = fetchTrackingTemplate(accountName, campaignName);
if (template) {
try {
campaign.urls().setTrackingTemplate(template);
Logger.log('Applied: ' + accountName + ' | ' + campaignName);
postExecutionLog(accountName, campaignName, 'apply_template', 'success', template, 'Applied', null);
} catch (applyError) {
Logger.log('Apply failed: ' + accountName + ' | ' + campaignName + ' | ' + applyError);
postExecutionLog(accountName, campaignName, 'apply_template', 'failed', template, null, String(applyError));
}
} else if (!LAST_FETCH_LOGGED) {
Logger.log('Skipped empty template: ' + accountName + ' | ' + campaignName);
postExecutionLog(accountName, campaignName, 'fetch_template', 'skipped', null, 'Empty template', null);
}
} catch (e) {
Logger.log('Campaign failed: ' + accountName + ' | ' + campaignName + ' | ' + e);
postExecutionLog(accountName, campaignName, 'fetch_template', 'failed', null, null, String(e));
}
}
}
function fetchTrackingTemplate(accountName, campaignName) {
var url = TRACKING_TEMPLATE_URL
+ '?google_account_name=' + encodeURIComponent(accountName)
+ '&campaign_name=' + encodeURIComponent(campaignName);
var response = fetchWithRetries(url);
var status = response.getResponseCode();
var body = response.getContentText();
if (status === 404) {
Logger.log('No template found: ' + accountName + ' | ' + campaignName);
postExecutionLog(accountName, campaignName, 'fetch_template', 'skipped', null, 'No template found', null);
LAST_FETCH_LOGGED = true;
return '';
}
if (status < 200 || status >= 300) {
Logger.log('Fetch failed: HTTP ' + status + ' | ' + body);
postExecutionLog(accountName, campaignName, 'fetch_template', 'failed', null, null, 'HTTP ' + status + ' | ' + body);
LAST_FETCH_LOGGED = true;
return '';
}
return String(body || '').trim();
}
function postExecutionLog(accountName, campaignName, action, status, template, message, errorMessage) {
try {
UrlFetchApp.fetch(LOG_URL, {
method: 'post',
contentType: 'application/json',
headers: {
'X-Import-Token': IMPORT_TOKEN
},
payload: JSON.stringify({
google_account_name: accountName,
campaign_name: campaignName,
script_type: SCRIPT_TYPE,
action: action,
status: status,
tracking_template: template,
message: message,
error_message: errorMessage,
executed_at: Utilities.formatDate(new Date(), AdsApp.currentAccount().getTimeZone(), 'yyyy-MM-dd HH:mm:ss')
}),
muteHttpExceptions: true
});
} catch (e) {
Logger.log('Log post failed: ' + e);
}
}
function fetchWithRetries(url) {
var lastResponse = null;
for (var i = 0; i < MAX_RETRIES; i++) {
try {
lastResponse = UrlFetchApp.fetch(url, {
method: 'get',
headers: {
'X-Import-Token': IMPORT_TOKEN
},
muteHttpExceptions: true
});
if (lastResponse.getResponseCode() < 500) {
return lastResponse;
}
} catch (e) {
Logger.log('Fetch attempt failed: ' + (i + 1) + ' | ' + e);
}
Utilities.sleep(1000 * (i + 1));
}
return lastResponse;
}
成本导入脚本
复制到 Google Ads Scripts 使用。
/**
* Google Ads Scripts -> ABOS Ad Cost import.
*
* Copy this script into Google Ads Scripts.
*/
var IMPORT_URL = 'https://lulutongagent.com/api/google-ads/costs/import';
var IMPORT_TOKEN = 'ABOS_GoogleAds_2026_x8K9mP2Q7';
var DEFAULT_PROJECT_ID = null;
var DEFAULT_WEBSITE_ID = null;
var DEFAULT_MERCHANT_ID = null;
var DEFAULT_FUND_POOL_ID = null;
var DEFAULT_CURRENCY = 'USD';
function main() {
if (typeof AdsManagerApp !== 'undefined') {
importForMcc();
return;
}
importForCurrentAccount();
}
function importForMcc() {
var accountIterator = AdsManagerApp.accounts().get();
while (accountIterator.hasNext()) {
var account = accountIterator.next();
AdsManagerApp.select(account);
importForCurrentAccount();
}
}
function importForCurrentAccount() {
var account = AdsApp.currentAccount();
var accountName = account.getName();
var currency = account.getCurrencyCode() || DEFAULT_CURRENCY;
var date = yesterday();
var query =
'SELECT campaign.name, metrics.cost_micros ' +
'FROM campaign ' +
'WHERE segments.date = "' + date.iso + '" ' +
'AND campaign.status != "REMOVED"';
var rows = AdsApp.search(query);
while (rows.hasNext()) {
var row = rows.next();
var cost = microsToMoney(row.metrics.costMicros);
if (cost <= 0) {
continue;
}
postCost({
date: date.iso,
google_account_name: accountName,
campaign_name: row.campaign.name,
cost: cost,
currency: currency,
project_id: DEFAULT_PROJECT_ID,
website_id: DEFAULT_WEBSITE_ID,
merchant_id: DEFAULT_MERCHANT_ID,
fund_pool_id: DEFAULT_FUND_POOL_ID,
notes: 'Imported from Google Ads Script'
});
}
}
function postCost(payload) {
var response = UrlFetchApp.fetch(IMPORT_URL, {
method: 'post',
contentType: 'application/json',
headers: {
'X-Import-Token': IMPORT_TOKEN
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
});
var status = response.getResponseCode();
var body = response.getContentText();
if (status < 200 || status >= 300) {
Logger.log('Import failed: HTTP ' + status + ' ' + body);
return;
}
Logger.log('Imported: ' + body);
}
function yesterday() {
var timeZone = AdsApp.currentAccount().getTimeZone();
var date = new Date();
date.setDate(date.getDate() - 1);
return {
iso: Utilities.formatDate(date, timeZone, 'yyyy-MM-dd'),
compact: Utilities.formatDate(date, timeZone, 'yyyyMMdd')
};
}
function microsToMoney(value) {
if (value === null || value === undefined) {
return 0;
}
return (parseFloat(String(value).replace(/,/g, '')) || 0) / 1000000;
}