Prácticas recomendadas

En esta página, se incluyen varias prácticas recomendadas para desarrollar con secuencias de comandos de Google Ads.

Selectores

Filtra con selectores

Cuando sea posible, usa filtros para solicitar solo las entidades que necesitas. Aplicar los filtros adecuados tiene los siguientes beneficios:

  • El código es más simple y fácil de entender.
  • La secuencia de comandos se ejecutará mucho más rápido.

Compara los siguientes fragmentos de código:

Enfoque de programación Fragmento de código
Cómo filtrar con selectores (recomendado)
var keywords = AdsApp.keywords()
    .withCondition('Clicks > 10')
    .forDateRange('LAST_MONTH')
    .get();
while (keywords.hasNext()) {
  var keyword = keywords.next();
  // Do work here.
}
Filtrar por código (no recomendado)
var keywords = AdsApp.keywords().get();

while (keywords.hasNext()) {
  var keyword = keywords.next();
  var stats = keyword.getStatsFor(
      'LAST_MONTH');
  if (stats.getClicks() > 10) {
    // Do work here.
  }
}

No se recomienda el segundo enfoque, ya que intenta recuperar la lista de todas las palabras clave de tu cuenta solo para aplicar un filtro a la lista.

Evitar desviar la jerarquía de la campaña

Cuando quieras recuperar entidades en un nivel en particular, usa un método de recopilación en ese nivel en lugar de recorrer toda la jerarquía de la campaña. Además de ser más simple, esto también tendrá un mejor rendimiento: el sistema no tendrá que leer innecesariamente todas las campañas y los grupos de anuncios.

Compara los siguientes fragmentos de código que recuperan todos los anuncios de tu cuenta:

Enfoque de programación Fragmento de código
Usa el método de recopilación adecuado (recomendado)

var ads = AdsApp.ads();

Recorre la jerarquía (no recomendado)
var campaigns = AdsApp.campaigns().get();
while (campaigns.hasNext()) {
  var adGroups = campaigns.next().
      adGroups().get();
  while (adGroups.hasNext()) {
    var ads = adGroups.next().ads().get();
    // Do your work here.
  }
}

No se recomienda el segundo enfoque, ya que intenta recuperar jerarquías completas de objetos (campañas, grupos de anuncios), mientras que solo se requieren anuncios.

Usa métodos de acceso parental específicos

A veces, debes obtener la entidad superior de un objeto recuperado. En este caso, debes usar un método de acceso proporcionado en lugar de recuperar jerarquías completas.

Compara los siguientes fragmentos de código que recuperan los grupos de anuncios que tienen anuncios de texto con más de 50 clics el mes pasado:

Enfoque de programación Fragmento de código
Usar el método de acceso superior adecuado (recomendado)
var ads = AdsApp.ads()
    .withCondition('Clicks > 50')
    .forDateRange('LAST_MONTH')
    .get();

while (ads.hasNext()) {
  var ad = ads.next();
  var adGroup = ad.getAdGroup();
  var campaign = ad.getCampaign();
  // Store (campaign, adGroup) to an array.
}
Recorre la jerarquía (no recomendado)
var campaigns = AdsApp.campaigns().get();
while (campaigns.hasNext()) {
  var adGroups = campaigns.next()
      .adGroups()
      .get();
  while (adGroups.hasNext()) {
    var ads = adGroups.ads()
       .withCondition('Clicks > 50')
       .forDateRange('LAST_MONTH')
       .get();
    if (ads.totalNumEntities() > 0) {
      // Store (campaign, adGroup) to an array.
    }
  }
}

El segundo enfoque no se recomienda, ya que recupera todas las jerarquías de campañas y grupos de anuncios en tu cuenta, mientras que solo necesitas un subconjunto de campañas y grupos de anuncios asociado a tu conjunto de anuncios. El primer enfoque se restringe a sí mismo para recuperar solo la colección de anuncios relevante y usa un método apropiado para acceder a sus objetos superiores.

Usa filtros superiores específicos

Para acceder a entidades dentro de una campaña o un grupo de anuncios específicos, usa un filtro específico en el selector en lugar de recuperar y, luego, recorrer una jerarquía.

Compara los siguientes fragmentos de código que recuperan la lista de anuncios de texto dentro de una campaña y un grupo de anuncios especificados que tuvieron más de 50 clics el mes pasado.

Enfoque de programación Fragmento de código
Usa los filtros de nivel superior adecuados (recomendado)
var ads = AdsApp.ads()
    .withCondition('CampaignName = "Campaign 1"')
    .withCondition('AdGroupName = "AdGroup 1"')
    .withCondition('Clicks > 50')
    .forDateRange('LAST_MONTH')
    .get();

while (ads.hasNext()) {
  var ad = ads.next();
  var adGroup = ad.getAdGroup();
  var campaign = ad.getCampaign();
  // Store (campaign, adGroup, ad) to
  // an array.
}
Recorre la jerarquía (no recomendado)
var campaigns = AdsApp.campaigns()
    .withCondition('Name = "Campaign 1"')
    .get();

while (campaigns.hasNext()) {
  var adGroups = campaigns.next()
      .adGroups()
      .withCondition('Name = "AdGroup 1"')
      .get();
  while (adGroups.hasNext()) {
    var ads = adGroups.ads()
       .withCondition('Clicks > 50')
       .forDateRange('LAST_MONTH')
       .get();
    while (ads.hasNext()) {
      var ad = ads.next();
      // Store (campaign, adGroup, ad) to
      // an array.
    }
  }
}

El segundo enfoque no se recomienda, ya que itera en la jerarquía de las campañas y los grupos de anuncios de tu cuenta, mientras que solo necesitas un conjunto seleccionado de anuncios, y sus campañas y grupos de anuncios superiores. El primer enfoque limita la iteración a la lista de anuncios aplicando un filtro específico para las entidades superiores en el selector.

Usa IDs para filtrar cuando sea posible

Cuando filtres entidades, es preferible hacerlo por sus IDs en lugar de otros campos.

Considera los siguientes fragmentos de código que seleccionan una campaña.

Enfoque de programación Fragmento de código
Filtrar por ID (recomendado)
var campaign = AdsApp.campaigns()
    .withIds([12345])
    .get()
    .next();
Filtrar por nombre (menos óptimo)
var campaign = AdsApp.campaigns()
    .withCondition('Name="foo"')
    .get()
    .next();

El segundo enfoque es menos óptimo, ya que filtramos por un campo que no es de ID.

Filtrar por IDs parentales siempre que sea posible

Cuando selecciones una entidad, filtra por IDs superiores siempre que sea posible. Esto hará que tus consultas sean más rápidas, ya que limita la lista de entidades que recuperan los servidores cuando se filtran los resultados.

Considera el siguiente fragmento de código que recupera un grupo de anuncios por su ID. Supongamos que se conoce el ID de la campaña superior.

Enfoque de programación Fragmento de código
Filtrar por IDs de campaña y grupo de anuncios (recomendado)
var adGroup = AdsApp.adGroups()
    .withIds([12345])
    .withCondition('CampaignId="54678"')
    .get()
    .next();
Filtrar solo por el ID del grupo de anuncios (menos óptimo)
var adGroup = AdsApp.adGroups()
    .withIds([12345])
    .get()
    .next();

Aunque ambos fragmentos de código proporcionan resultados idénticos, el filtrado adicional en el fragmento de código 1 con un ID superior (CampaignId="54678") hace que el código sea más eficiente, ya que restringe la lista de entidades que el servidor debe iterar cuando filtra los resultados.

Usa etiquetas cuando hay demasiadas condiciones de filtrado

Cuando tienes demasiadas condiciones de filtrado, es una buena idea crear una etiqueta para las entidades que procesas y usarla para filtrar tus entidades.

Considera el siguiente fragmento de código que recupera una lista de campañas por su nombre.

Enfoque de programación Fragmento de código
Usa una etiqueta (recomendado)
var label = AdsApp.labels()
    .withCondition('Name = "My Label"')
    .get()
    .next();
var campaigns = label.campaigns.get();
while (campaigns.hasNext()) {
  var campaign = campaigns.next();
  // Do more work
}
Cómo compilar selectores complejos (no recomendado)
var campaignNames = [‘foo’, ‘bar’, ‘baz’];

for (var i = 0; i < campaignNames.length; i++) {
  campaignNames[i] = '"' + campaignNames[i] + '"';
}

var campaigns = AdsApp.campaigns
    .withCondition('CampaignName in [' + campaignNames.join(',') + ']')
    .get();

while (campaigns.hasNext()) {
  var campaign = campaigns.next();
  // Do more work.
}

Si bien ambos fragmentos de código te brindan un nivel de rendimiento similar, el segundo enfoque tiende a generar un código más complejo a medida que aumenta la cantidad de condiciones en tu selector. También es más fácil aplicar la etiqueta a una entidad nueva que editar la secuencia de comandos para incluir una entidad nueva.

Limita la cantidad de condiciones en tu cláusula IN

Cuando se ejecutan secuencias de comandos, un caso de uso común es ejecutar un informe para una lista de entidades. Por lo general, los desarrolladores logran esto mediante la construcción de una consulta AWQL muy larga que filtra los IDs de entidad con una cláusula IN. Este enfoque funciona bien cuando la cantidad de entidades es limitada. Sin embargo, a medida que aumenta la longitud de la consulta, el rendimiento de la secuencia de comandos se deteriora debido a dos motivos:

  • Una consulta más larga tarda más en analizarse.
  • Cada ID que agregues a una cláusula IN es una condición adicional que se debe evaluar y, por lo tanto, lleva más tiempo.

En esas condiciones, es preferible aplicar una etiqueta a las entidades y, luego, filtrar por LabelId.

Enfoque de programación Fragmento de código
Aplica una etiqueta y filtra por labelID (recomendado)
// The label applied to the entity is "Report Entities"
var label = AdsApp.labels()
    .withCondition('LabelName contains "Report Entities"')
    .get()
    .next();

var report = AdsApp.report('SELECT AdGroupId, Id, Clicks, ' +
    'Impressions, Cost FROM KEYWORDS_PERFORMANCE_REPORT ' +
    'WHERE LabelId = "' + label.getId() + '"');
Compila una consulta larga con la cláusula IN (no recomendada)
var report = AdsApp.report('SELECT AdGroupId, Id, Clicks, ' +
    'Impressions, Cost FROM KEYWORDS_PERFORMANCE_REPORT WHERE ' +
    'AdGroupId IN (123, 456) and Id in (123,345, 456…)');

Actualizaciones de la cuenta

Cambios por lotes

Cuando realizas cambios en una entidad de Google Ads, las secuencias de comandos de Google Ads no ejecutan el cambio de inmediato. En su lugar, intenta combinar varios cambios en lotes para poder emitir una sola solicitud que realice varios cambios. Este enfoque hace que tus secuencias de comandos sean más rápidas y reduce la carga en los servidores de Google Ads. Sin embargo, hay algunos patrones de código que obligan a las secuencias de comandos de Google Ads a vaciar su lote de operaciones con frecuencia, lo que hace que la secuencia de comandos se ejecute lentamente.

Considera la siguiente secuencia de comandos que actualiza las ofertas de una lista de palabras clave.

Enfoque de programación Fragmento de código
Hacer un seguimiento de los elementos actualizados (recomendado)
var keywords = AdsApp.keywords()
    .withCondition('Clicks > 50')
    .withCondition('CampaignName = "Campaign 1"')
    .withCondition('AdGroupName = "AdGroup 1"')
    .forDateRange('LAST_MONTH')
    .get();

var list = [];
while (keywords.hasNext()) {
  var keyword = keywords.next();
  keyword.bidding().setCpc(1.5);
  list.push(keyword);
}

for (var i = 0; i < list.length; i++) {
  var keyword = list[i];
  Logger.log('%s, %s', keyword.getText(),
      keyword.bidding().getCpc());
}
Recuperar elementos actualizados en un bucle ajustado (no recomendado)
var keywords = AdsApp.keywords()
    .withCondition('Clicks > 50')
    .withCondition('CampaignName = "Campaign 1"')
    .withCondition('AdGroupName = "AdGroup 1"')
    .forDateRange('LAST_MONTH')
    .get();

while (keywords.hasNext()) {
  var keyword = keywords.next();
  keyword.bidding().setCpc(1.5);
  Logger.log('%s, %s', keyword.getText(),
      keyword.bidding().getCpc());
}

No se recomienda el segundo enfoque, ya que la llamada a keyword.bidding().getCpc() fuerza a las secuencias de comandos de Google Ads a vaciar la operación setCpc() y ejecutar solo una operación a la vez. Si bien el primer enfoque es similar al segundo, tiene el beneficio adicional de admitir el procesamiento por lotes, ya que la llamada a getCpc() se realiza en un bucle independiente del que se llama a setCpc().

Usa compiladores cuando sea posible

Las secuencias de comandos de Google Ads admiten dos formas de crear objetos nuevos: compiladores y métodos de creación. Los compiladores son más flexibles que los métodos de creación, ya que te brindan acceso al objeto que se crea a partir de la llamada a la API.

Considera los siguientes fragmentos de código:

Enfoque de programación Fragmento de código
Cómo usar los compiladores (recomendado)
var operation = adGroup.newKeywordBuilder()
    .withText('shoes')
    .build();
var keyword = operation.getResult();
Cómo usar métodos de creación (no recomendado)
adGroup.createKeyword('shoes');
var keyword = adGroup.keywords()
    .withCondition('KeywordText="shoes"')
    .get()
    .next();

No se prefiere el segundo enfoque debido a la operación de selección adicional que implica recuperar la palabra clave. Además, los métodos de creación también dejaron de estar disponibles.

Sin embargo, ten en cuenta que, si se usan de forma incorrecta, los compiladores pueden impedir que las secuencias de comandos de Google Ads agrupen sus operaciones.

Considera los siguientes fragmentos de código que crean una lista de palabras clave y, luego, imprimen el ID de las palabras clave recién creadas:

Enfoque de programación Fragmento de código
Hacer un seguimiento de los elementos actualizados (recomendado)
var keywords = [‘foo’, ‘bar’, ‘baz’];

var list = [];
for (var i = 0; i < keywords.length; i++) {
  var operation = adGroup.newKeywordBuilder()
      .withText(keywords[i])
      .build();
  list.push(operation);
}

for (var i = 0; i < list.length; i++) {
  var operation = list[i];
  var result = operation.getResult();
  Logger.log('%s %s', result.getId(),
      result.getText());
}
Recupera elementos actualizados en un bucle ajustado (no recomendado)
var keywords = [‘foo’, ‘bar’, ‘baz’];

for (var i = 0; i < keywords.length; i++) {
  var operation = adGroup.newKeywordBuilder()
      .withText(keywords[i])
      .build();
  var result = operation.getResult();
  Logger.log('%s %s', result.getId(),
      result.getText());
}

No se prefiere el segundo enfoque porque llama a operation.getResult() dentro del mismo bucle que crea la operación, lo que obliga a las secuencias de comandos de Google Ads a ejecutar una operación a la vez. Si bien el primer enfoque es similar, permite el procesamiento por lotes, ya que llamamos a operation.getResult() en un bucle diferente del que se creó.

Considera usar cargas masivas para actualizaciones grandes

Una tarea común que realizan los desarrolladores es ejecutar informes y actualizar las propiedades de las entidades (por ejemplo, ofertas de palabras clave) según los valores de rendimiento actuales. Cuando tienes que actualizar una gran cantidad de entidades, las cargas masivas suelen brindar un mejor rendimiento. Por ejemplo, considera las siguientes secuencias de comandos que aumentan el MaxCpc de las palabras clave cuyo TopImpressionPercentage > 0.4 del último mes es el siguiente:

Enfoque de programación Fragmento de código
Cómo usar la carga masiva (recomendado)

var report = AdsApp.report(
  'SELECT AdGroupId, Id, CpcBid FROM KEYWORDS_PERFORMANCE_REPORT ' +
  'WHERE TopImpressionPercentage > 0.4 DURING LAST_MONTH');

var upload = AdsApp.bulkUploads().newCsvUpload([
  report.getColumnHeader('AdGroupId').getBulkUploadColumnName(),
  report.getColumnHeader('Id').getBulkUploadColumnName(),
  report.getColumnHeader('CpcBid').getBulkUploadColumnName()]);
upload.forCampaignManagement();

var reportRows = report.rows();
while (reportRows.hasNext()) {
  var row = reportRows.next();
  row['CpcBid'] = row['CpcBid'] + 0.02;
  upload.append(row.formatForUpload());
}

upload.apply();
Seleccionar y actualizar palabras clave por ID (menos óptimo)
var reportRows = AdsApp.report('SELECT AdGroupId, Id, CpcBid FROM ' +
    'KEYWORDS_PERFORMANCE_REPORT WHERE TopImpressionPercentage > 0.4 ' +
    ' DURING LAST_MONTH')
    .rows();

var map = {
};

while (reportRows.hasNext()) {
  var row = reportRows.next();
  var adGroupId = row['AdGroupId'];
  var id = row['Id'];

  if (map[adGroupId] == null) {
    map[adGroupId] = [];
  }
  map[adGroupId].push([adGroupId, id]);
}

for (var key in map) {
  var keywords = AdsApp.keywords()
      .withCondition('AdGroupId="' + key + '"')
      .withIds(map[key])
      .get();

  while (keywords.hasNext()) {
    var keyword = keywords.next();
    keyword.bidding().setCpc(keyword.bidding().getCpc() + 0.02);
  }
}

Si bien el segundo enfoque te brinda un rendimiento bastante bueno, se prefiere el primero en este caso, ya que

  • Las secuencias de comandos de Google Ads tienen un límite en la cantidad de objetos que se pueden recuperar o actualizar en una sola ejecución, y las operaciones de selección y actualización en el segundo enfoque se consideran para ese límite.

  • Las cargas masivas tienen límites más altos en términos de la cantidad de entidades que pueden actualizar y el tiempo de ejecución general.

Cómo agrupar tus cargas masivas por campañas

Cuando crees tus cargas masivas, intenta agrupar tus operaciones por la campaña superior. Esto aumenta la eficiencia y disminuye las posibilidades de que se produzcan cambios o errores de simultaneidad en conflicto.

Considera dos tareas de carga masiva que se ejecutan en paralelo. Una detiene los anuncios en un grupo de anuncios; la otra ajusta las ofertas de palabras clave. Aunque las operaciones no estén relacionadas, estas pueden aplicarse a entidades del mismo grupo de anuncios (o a dos grupos de anuncios diferentes de la misma campaña). Cuando esto suceda, el sistema bloqueará la entidad superior (el grupo de anuncios o la campaña compartidos), lo que provocará que las tareas de carga masiva se bloqueen entre sí.

Las secuencias de comandos de Google Ads pueden optimizar la ejecución dentro de una sola tarea de carga masiva, por lo que lo más sencillo es ejecutar solo una tarea de carga masiva por cuenta a la vez. Si decides ejecutar más de una carga masiva por cuenta, asegúrate de que las cargas masivas funcionen en una lista de campañas mutuamente excluyentes (y sus entidades secundarias) para obtener un rendimiento óptimo.

Informes

Usa informes para recuperar estadísticas

Cuando deseas recuperar grandes cantidades de entidades y sus estadísticas, a menudo es mejor usar informes en lugar de métodos estándar de AdsApp. Se prefiere el uso de informes por los siguientes motivos:

  • Los informes proporcionan un mejor rendimiento para las consultas grandes.
  • Los informes no alcanzarán las cuotas de recuperación normales.

Compara los siguientes fragmentos de código que recuperan los clics, las impresiones, el costo y el texto de todas las palabras clave que recibieron más de 50 clics el mes pasado:

Enfoque de programación Fragmento de código
Usar informes (recomendado)
  report = AdsApp.search(
      'SELECT ' +
      '   ad_group_criterion.keyword.text, ' +
      '   metrics.clicks, ' +
      '   metrics.cost_micros, ' +
      '   metrics.impressions ' +
      'FROM ' +
      '   keyword_view ' +
      'WHERE ' +
      '   segments.date DURING LAST_MONTH ' +
      '   AND metrics.clicks > 50');
  while (report.hasNext()) {
    var row = report.next();
    Logger.log('Keyword: %s Impressions: %s ' +
        'Clicks: %s Cost: %s',
        row.adGroupCriterion.keyword.text,
        row.metrics.impressions,
        row.metrics.clicks,
        row.metrics.cost);
  }
Usa iteradores de AdsApp (no recomendado)
var keywords = AdsApp.keywords()
    .withCondition('metrics.clicks > 50')
    .forDateRange('LAST_MONTH')
    .get();
while (keywords.hasNext()) {
  var keyword = keywords.next();
  var stats = keyword.getStatsFor('LAST_MONTH');
  Logger.log('Keyword: %s Impressions: %s ' +
      'Clicks: %s Cost: %s',
      keyword.getText(),
      stats.getImpressions(),
      stats.getClicks(),
      stats.getCost());
}

No se prefiere el segundo enfoque porque itera sobre las palabras clave y recupera las estadísticas una entidad a la vez. En este caso, los informes tienen un mejor rendimiento, ya que recuperan todos los datos en una sola llamada y los transmiten según sea necesario. Además, las palabras clave recuperadas en el segundo enfoque se contabilizan en la cuota de tu secuencia de comandos para la cantidad de entidades recuperadas con una llamada a get().

Usa la búsqueda en lugar del informe

El método de informe se compiló para la infraestructura anterior y mostrará los resultados en un formato plano, incluso si usas GAQL. Esto significa que debe transformar los resultados de la consulta para que coincidan con el estilo anterior, que no es compatible con todos los campos y agrega sobrecarga a cada llamada.

Te sugerimos que uses la búsqueda para aprovechar todas las funciones de los nuevos informes de la API de Google Ads.

Prefiere GAQL a AWQL

Aunque AWQL todavía es compatible con las consultas de informes y las llamadas a withCondition, se ejecuta a través de una capa de traducción que no tiene compatibilidad total con AWQL verdadero. Para tener un control total sobre tus consultas, asegúrate de usar GAQL.

Si tienes consultas de AWQL existentes que deseas traducir, tenemos una herramienta de migración de consultas para ayudarte.

No selecciones más filas de las que necesitas.

La velocidad de ejecución de los informes (y selectores) se basa en la cantidad total de filas que devuelve el informe, independientemente de si iteras por ellas. Esto significa que siempre debes usar filtros específicos para minimizar el conjunto de resultados tanto como sea posible para que coincida con tu caso de uso.

Por ejemplo, supongamos que deseas buscar grupos de anuncios con ofertas fuera de algún rango específico. Sería más rápido realizar dos consultas separadas, una para ofertas por debajo del umbral inferior y otra para ofertas que superan el umbral superior, que recuperar todos los grupos de anuncios y omitir los que no te interesan.

Enfoque de programación Fragmento de código
Usa dos consultas (recomendado)
var adGroups = []
var report = AdsApp.search(
    'SELECT ad_group.name, ad_group.cpc_bid_micros' +
    ' FROM ad_group WHERE ad_group.cpc_bid_micros < 1000000');

while (report.hasNext()) {
  var row = report.next();
  adGroups.push(row.adGroup);
}
var report = AdsApp.search(
    'SELECT ad_group.name, ad_group.cpc_bid_micros' +
    ' FROM ad_group WHERE ad_group.cpc_bid_micros > 2000000');

while (report.hasNext()) {
  var row = report.next();
  adGroups.push(row.adGroup);
}
Cómo filtrar desde una búsqueda genérica (no recomendado)
var adGroups = []
var report = AdsApp.search(
    'SELECT ad_group.name, ad_group.cpc_bid_micros' +
    ' FROM ad_group');

while (report.hasNext()) {
  var row = report.next();
  var cpcBidMicros = row.adGroup.cpcBidMicros;
  if (cpcBidMicros < 1000000 || cpcBidMicros > 2000000) {
    adGroups.push(row.adGroup);
  }
}

Secuencias de comandos de Ad Manager (MCC)

Prefiere executeInParallel en lugar de la ejecución en serie

Cuando escribas secuencias de comandos para cuentas de administrador, usa executeInParallel() en lugar de la ejecución en serie siempre que sea posible. executeInParallel() le brinda a tu secuencia de comandos más tiempo de procesamiento (hasta una hora) y hasta 30 minutos por cuenta procesada (en lugar de 30 minutos combinados para la ejecución en serie). Consulta nuestra página de límites para obtener más detalles.

Hojas de cálculo

Usa operaciones por lotes cuando actualices hojas de cálculo

Cuando actualices las hojas de cálculo, intenta usar los métodos de operación masiva (por ejemplo, getRange()) en lugar de los métodos que actualizan una celda a la vez.

Considera el siguiente fragmento de código que genera un patrón fractal en una hoja de cálculo.

Enfoque de programación Fragmento de código
Actualiza un rango de celdas en una sola llamada (recomendado)
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
  xcoord = xmin;
  colors[y] = new Array(100);
  for (var x = 0; x < 100; x++) {
    colors[y][x] = getColor_(xcoord, ycoord);
    xcoord += xincrement;
  }
  ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
Actualiza una celda a la vez (no recomendado)
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
  xcoord = xmin;
  for (var x = 0; x < 100; x++) {
    var c = getColor_(xcoord, ycoord);
    cell.offset(y, x).setBackgroundColor(c);
    xcoord += xincrement;
  }
  ycoord -= yincrement;
  SpreadsheetApp.flush();
}

Si bien Hojas de cálculo de Google intenta optimizar el segundo fragmento de código almacenando en caché los valores, su rendimiento sigue siendo bajo en comparación con el primer fragmento debido a la cantidad de llamadas a la API que se realizan.