Skip to main content

Add google static maps to an attachments field


Add static Google Maps to attachments based on addresses in a table.



Source Code
/**

 * Copyright 2020 Bocoup

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to

 * deal in the Software without restriction, including without limitation the

 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

 * sell copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

 * IN THE SOFTWARE.

 */



/**

 * Airtable attach google static maps script

 *

 * This script looks at each row and adds google map images to an attachment

 * field cell in that row based on the addresses in the row. Rows with no

 * addresses or that already has attachments are skipped.

 *

 * This script uses Google's static map API. See for more info:

 * https://developers.google.com/maps/documentation/maps-static/intro

 *

 * **Notes on adapting this script.**

 *

 * Before running this script set the apiKey, tableName, addressFieldNames, and

 * mapTileAttachmentFieldName variables below. After that it can be run at any

 * time and it will update new records or old records with an empty attachments

 * cell. Further customizations can be made to the maps by modifying

 * staticmapOptions further down.

 */



'use strict';



// Google Maps API key

// See google's documentation to get a key.

// https://developers.google.com/maps/documentation/javascript/get-api-key

//

// The text of this script including the apiKey will be visible to everyone who

// can view this airtable base.

let apiKey = '**************';



// The name of the table this script will update.

let tableName = 'Map Table';

// Names of fields with an address to get a map for. Each field can have 0 or 1

// addresses.

let addressFieldNames = [

    'Map Address',

    // 'Start Address',

    // 'Special Address',

];

// Name of an attachments field that will be updated with static google map images.

let mapTileAttachmentFieldName = 'Map Attachments';



//

// After this line is the script logic. To use this script as-is, you do not need

// to edit anything after this point.

//



let RECORD_BATCH_COUNT = 50;



let table = base.getTable(tableName);

let allRecords = await table.selectRecordsAsync({

    // In the case there are a lot of fields, get the address and map tile fields only.

    fields: [...addressFieldNames, mapTileAttachmentFieldName],

});



let updates = [];



// Iterate every record in the table.

for (let recordId of allRecords.recordIds) {

    let record = allRecords.getRecord(recordId);



    // Skip records that have no addresses or already have attached images.

    if (

        !addressFieldNames.some(fieldName => record.getCellValue(fieldName)) ||

        record.getCellValue(mapTileAttachmentFieldName)

    ) {

        continue;

    }



    // Create google static map api urls from address fields for this record.

    let urls = [];

    for (let fieldName of addressFieldNames) {

        let staticmapOptions = {

            // The Google API Key. Required.

            key: apiKey,

            // The center of the returned map. Can be latitude, longitude

            // coordinates or an address. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Locations

            center: record.getCellValue(fieldName),

            // Smaller numbers zoom out, larger numbers zoom in. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Zoomlevels

            zoom: 17,



            // 640 by 640 pixels is the largest normal resolution at scale 1. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Largerimagesizes

            size: [640, 640],

            // Scale can be 1 or 2. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#scale_values

            scale: 1,

            // Which image format to return. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#ImageFormats

            format: 'jpg',

            // Maptype can be roadmap, terrain, hybrid, or streetview. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#MapTypes

            maptype: 'roadmap',

            // Language and region are optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#map-parameters

            language: 'en-US',

            region: 'us',



            // There are other options.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#feature-parameters

        };



        let staticmapParameters = Object.entries(staticmapOptions).map(([key, value]) => {

            if (key === 'size') {

                return `size=${value[0]}x${value[1]}`;

            }

            return `${key}=${encodeURIComponent(value)}`;

        });

        let staticmapUrl = `https://maps.googleapis.com/maps/api/staticmap?${staticmapParameters.join('&')}`;



        // Add a attachment cell object to urls to add to the record update.

        urls.push({url: staticmapUrl});

    }



    // Create record update with map urls.

    updates.push({id: record.id, fields: {[mapTileAttachmentFieldName]: urls}});

}



output.markdown(`Prepared ${updates.length} row updates out of ${allRecords.recordIds.length} in the table.`);



// For subsets of updates

for (let i = 0; i < updates.length; i += RECORD_BATCH_COUNT) {

    // Update table with a subset of all the updates ready to be made.

    output.markdown(`Applying update ${i + 1} through ${Math.min(i + RECORD_BATCH_COUNT, updates.length)} of ${updates.length}.`);

    await table.updateRecordsAsync(updates.slice(i, i + RECORD_BATCH_COUNT));

}



output.markdown('Done.');



This script looks at each row and adds google map images to an attachment field cell in that row based on the addresses in the row. Rows with no addresses or that already has attachments are skipped.


This script uses Google’s static map API. See for more info:




Notes on adapting this script.


Before running this script set the apiKey, tableName, addressFieldNames, and mapTileAttachmentFieldName variables below. After that it can be run at any time and it will update new records or old records with an empty attachments cell. Further customizations can be made to the maps by modifying staticmapOptions further down.


Made this to help do things like what is mentioned in Map in Page Designer?.

22 replies

  • Inspiring
  • 63 replies
  • June 15, 2020

Love it! Could see this be super useful in so many ways, thanks for sharing Z_Goddard!


  • Participating Frequently
  • 8 replies
  • June 15, 2020

New to Scripting… I used the Script successfully once, then decided to change the ZOOM level. I deleted the previous Attachments and ran the script again. The Script runs but the attachments are bad files. what am i doing wrong?


  • Author
  • New Participant
  • 3 replies
  • June 16, 2020
Eddie_Kaeser wrote:

New to Scripting… I used the Script successfully once, then decided to change the ZOOM level. I deleted the previous Attachments and ran the script again. The Script runs but the attachments are bad files. what am i doing wrong?


@Eddie_Kaeser what ZOOM level did you change it to?


  • Participating Frequently
  • 8 replies
  • June 16, 2020
Z_Goddard wrote:

@Eddie_Kaeser what ZOOM level did you change it to?



  1. it actually is working now. guess I was impatient. Thanks for the Script. it works great and is extremely helpful!


Has anyone added map markers to the script? I see you can add markers in the Developer Guide, but I am new to scripting so a bit confused on how to add to the script.


I would also love to see this adapted to a street view image! I am using airtable for a plumbing company, so would be valuable to have a street view image of the house to add to job tickets.


Melissa_Bradley wrote:

Has anyone added map markers to the script? I see you can add markers in the Developer Guide, but I am new to scripting so a bit confused on how to add to the script.


@Z_Goddard Do you know how to add map markers to the script? Your script is fantastic for our use case, but not much help without map markers unfortunately. Thanks!


  • Author
  • New Participant
  • 3 replies
  • July 13, 2020
Melissa_Bradley wrote:

@Z_Goddard Do you know how to add map markers to the script? Your script is fantastic for our use case, but not much help without map markers unfortunately. Thanks!


Hi @Melissa_Bradley,


You can change the script to add markers. One way to change it would be to replace center in the staticmapOptions object to markers with something like:



// Add markers to the map. This is a set of locations written as

// coordinates or addresses. Required.

// See for more info:

// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

markers: ‘color:black|’ + record.getCellValue(fieldName).split(’\n’).join(’|’),



Here is the full script edited with that change. In this version it will the same configured field with a location per line to make maps with markers instead of just specifying the center.



Source Code with Markers change
/**

 * Copyright 2020 Bocoup

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to

 * deal in the Software without restriction, including without limitation the

 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

 * sell copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

 * IN THE SOFTWARE.

 */



/**

 * Airtable attach google static maps script

 *

 * This script looks at each row and adds google map images to an attachment

 * field cell in that row based on the addresses in the row. Rows with no

 * addresses or that already has attachments are skipped.

 *

 * This script uses Google's static map API. See for more info:

 * https://developers.google.com/maps/documentation/maps-static/intro

 *

 * **Notes on adapting this script.**

 *

 * Before running this script set the apiKey, tableName, addressFieldNames, and

 * mapTileAttachmentFieldName variables below. After that it can be run at any

 * time and it will update new records or old records with an empty attachments

 * cell. Further customizations can be made to the maps by modifying

 * staticmapOptions further down.

 */



'use strict';



// Google Maps API key

// See google's documentation to get a key.

// https://developers.google.com/maps/documentation/javascript/get-api-key

//

// The text of this script including the apiKey will be visible to everyone who

// can view this airtable base.

let apiKey = '**************';



// The name of the table this script will update.

let tableName = 'Map Table';

// Names of fields with an address to get a map for. Each field can have 0 or 1

// addresses.

let addressFieldNames = [

    'Map Address',

    // 'Start Address',

    // 'Special Address',

];

// Name of an attachments field that will be updated with static google map images.

let mapTileAttachmentFieldName = 'Map Attachments';



//

// After this line is the script logic. To use this script as-is, you do not need

// to edit anything after this point.

//



let RECORD_BATCH_COUNT = 50;



let table = base.getTable(tableName);

let allRecords = await table.selectRecordsAsync({

    // In the case there are a lot of fields, get the address and map tile fields only.

    fields: [...addressFieldNames, mapTileAttachmentFieldName],

});



let updates = [];



// Iterate every record in the table.

for (let recordId of allRecords.recordIds) {

    let record = allRecords.getRecord(recordId);



    // Skip records that have no addresses or already have attached images.

    if (

        !addressFieldNames.some(fieldName => record.getCellValue(fieldName)) ||

        record.getCellValue(mapTileAttachmentFieldName)

    ) {

        continue;

    }



    // Create google static map api urls from address fields for this record.

    let urls = [];

    for (let fieldName of addressFieldNames) {

        let staticmapOptions = {

            // The Google API Key. Required.

            key: apiKey,

            // Add markers to the map. This is a set of locations written as

            // coordinates or addresses. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

            markers: 'color:black|' + record.getCellValue(fieldName).split('\n').join('|'),

            // The center of the returned map. Can be latitude, longitude

            // coordinates or an address. Optional if markers is set.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Locations

            // center: '',

            // Smaller numbers zoom out, larger numbers zoom in. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Zoomlevels

            zoom: 17,



            // 640 by 640 pixels is the largest normal resolution at scale 1. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Largerimagesizes

            size: [640, 640],

            // Scale can be 1 or 2. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#scale_values

            scale: 1,

            // Which image format to return. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#ImageFormats

            format: 'jpg',

            // Maptype can be roadmap, terrain, hybrid, or streetview. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#MapTypes

            maptype: 'roadmap',

            // Language and region are optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#map-parameters

            language: 'en-US',

            region: 'us',



            // There are other options.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#feature-parameters

        };



        let staticmapParameters = Object.entries(staticmapOptions).map(([key, value]) => {

            if (key === 'size') {

                return `size=${value[0]}x${value[1]}`;

            }

            return `${key}=${encodeURIComponent(value)}`;

        });

        let staticmapUrl = `https://maps.googleapis.com/maps/api/staticmap?${staticmapParameters.join('&')}`;



        // Add a attachment cell object to urls to add to the record update.

        urls.push({url: staticmapUrl});

    }



    // Create record update with map urls.

    updates.push({id: record.id, fields: {[mapTileAttachmentFieldName]: urls}});

}



output.markdown(`Prepared ${updates.length} row updates out of ${allRecords.recordIds.length} in the table.`);



// For subsets of updates

for (let i = 0; i < updates.length; i += RECORD_BATCH_COUNT) {

    // Update table with a subset of all the updates ready to be made.

    output.markdown(`Applying update ${i + 1} through ${Math.min(i + RECORD_BATCH_COUNT, updates.length)} of ${updates.length}.`);

    await table.updateRecordsAsync(updates.slice(i, i + RECORD_BATCH_COUNT));

}



output.markdown('Done.');



  • Participating Frequently
  • 10 replies
  • July 13, 2020
Z_Goddard wrote:

Hi @Melissa_Bradley,


You can change the script to add markers. One way to change it would be to replace center in the staticmapOptions object to markers with something like:



// Add markers to the map. This is a set of locations written as

// coordinates or addresses. Required.

// See for more info:

// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

markers: ‘color:black|’ + record.getCellValue(fieldName).split(’\n’).join(’|’),



Here is the full script edited with that change. In this version it will the same configured field with a location per line to make maps with markers instead of just specifying the center.



Source Code with Markers change
/**

 * Copyright 2020 Bocoup

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to

 * deal in the Software without restriction, including without limitation the

 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

 * sell copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

 * IN THE SOFTWARE.

 */



/**

 * Airtable attach google static maps script

 *

 * This script looks at each row and adds google map images to an attachment

 * field cell in that row based on the addresses in the row. Rows with no

 * addresses or that already has attachments are skipped.

 *

 * This script uses Google's static map API. See for more info:

 * https://developers.google.com/maps/documentation/maps-static/intro

 *

 * **Notes on adapting this script.**

 *

 * Before running this script set the apiKey, tableName, addressFieldNames, and

 * mapTileAttachmentFieldName variables below. After that it can be run at any

 * time and it will update new records or old records with an empty attachments

 * cell. Further customizations can be made to the maps by modifying

 * staticmapOptions further down.

 */



'use strict';



// Google Maps API key

// See google's documentation to get a key.

// https://developers.google.com/maps/documentation/javascript/get-api-key

//

// The text of this script including the apiKey will be visible to everyone who

// can view this airtable base.

let apiKey = '**************';



// The name of the table this script will update.

let tableName = 'Map Table';

// Names of fields with an address to get a map for. Each field can have 0 or 1

// addresses.

let addressFieldNames = [

    'Map Address',

    // 'Start Address',

    // 'Special Address',

];

// Name of an attachments field that will be updated with static google map images.

let mapTileAttachmentFieldName = 'Map Attachments';



//

// After this line is the script logic. To use this script as-is, you do not need

// to edit anything after this point.

//



let RECORD_BATCH_COUNT = 50;



let table = base.getTable(tableName);

let allRecords = await table.selectRecordsAsync({

    // In the case there are a lot of fields, get the address and map tile fields only.

    fields: [...addressFieldNames, mapTileAttachmentFieldName],

});



let updates = [];



// Iterate every record in the table.

for (let recordId of allRecords.recordIds) {

    let record = allRecords.getRecord(recordId);



    // Skip records that have no addresses or already have attached images.

    if (

        !addressFieldNames.some(fieldName => record.getCellValue(fieldName)) ||

        record.getCellValue(mapTileAttachmentFieldName)

    ) {

        continue;

    }



    // Create google static map api urls from address fields for this record.

    let urls = [];

    for (let fieldName of addressFieldNames) {

        let staticmapOptions = {

            // The Google API Key. Required.

            key: apiKey,

            // Add markers to the map. This is a set of locations written as

            // coordinates or addresses. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

            markers: 'color:black|' + record.getCellValue(fieldName).split('\n').join('|'),

            // The center of the returned map. Can be latitude, longitude

            // coordinates or an address. Optional if markers is set.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Locations

            // center: '',

            // Smaller numbers zoom out, larger numbers zoom in. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Zoomlevels

            zoom: 17,



            // 640 by 640 pixels is the largest normal resolution at scale 1. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Largerimagesizes

            size: [640, 640],

            // Scale can be 1 or 2. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#scale_values

            scale: 1,

            // Which image format to return. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#ImageFormats

            format: 'jpg',

            // Maptype can be roadmap, terrain, hybrid, or streetview. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#MapTypes

            maptype: 'roadmap',

            // Language and region are optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#map-parameters

            language: 'en-US',

            region: 'us',



            // There are other options.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#feature-parameters

        };



        let staticmapParameters = Object.entries(staticmapOptions).map(([key, value]) => {

            if (key === 'size') {

                return `size=${value[0]}x${value[1]}`;

            }

            return `${key}=${encodeURIComponent(value)}`;

        });

        let staticmapUrl = `https://maps.googleapis.com/maps/api/staticmap?${staticmapParameters.join('&')}`;



        // Add a attachment cell object to urls to add to the record update.

        urls.push({url: staticmapUrl});

    }



    // Create record update with map urls.

    updates.push({id: record.id, fields: {[mapTileAttachmentFieldName]: urls}});

}



output.markdown(`Prepared ${updates.length} row updates out of ${allRecords.recordIds.length} in the table.`);



// For subsets of updates

for (let i = 0; i < updates.length; i += RECORD_BATCH_COUNT) {

    // Update table with a subset of all the updates ready to be made.

    output.markdown(`Applying update ${i + 1} through ${Math.min(i + RECORD_BATCH_COUNT, updates.length)} of ${updates.length}.`);

    await table.updateRecordsAsync(updates.slice(i, i + RECORD_BATCH_COUNT));

}



output.markdown('Done.');



This worked great!! Thank you so much!


  • New Participant
  • 4 replies
  • August 24, 2020

Incredibly new to scripting here but trying out your fabulous work… I’m getting the error:


TypeError: output.markdown is not a function

at main on line 151


Do you have a sec to point me where I might be going wrong?


EDIT: Okay I changed output.markdown to console.log and runs succesfully (although just getting blank attachments which then vanish affter a moment so more debugging required here 🙂


Melissa_Bradley wrote:

I would also love to see this adapted to a street view image! I am using airtable for a plumbing company, so would be valuable to have a street view image of the house to add to job tickets.


This video could interested you


Hi everyone,


Does anyone know how can use my own google maps style using my API Key and my MAP_ID ?


Thanks in advance 🙂


  • Participating Frequently
  • 10 replies
  • December 21, 2020
Thibaud_Donzier wrote:

This video could interested you



Wow, this is exactly the functionality I need, but the code went a little over my head. Thanks for sharing!


  • Participating Frequently
  • 6 replies
  • April 7, 2021

Was there ever a way figured out to pull a street view image and drop it in an attachments folder based off an address?


  • New Participant
  • 1 reply
  • September 8, 2021

Hi, when I run this I get an attachment but Airtable does not show the image preview.


I get a paperclip and then when opened it says previews are not available for this file type.

But it is outputting as a jpeg right?

Also, opening the link takes me to the correct location in Google Maps. Any tips?


Z_Goddard wrote:

Hi @Melissa_Bradley,


You can change the script to add markers. One way to change it would be to replace center in the staticmapOptions object to markers with something like:



// Add markers to the map. This is a set of locations written as

// coordinates or addresses. Required.

// See for more info:

// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

markers: ‘color:black|’ + record.getCellValue(fieldName).split(’\n’).join(’|’),



Here is the full script edited with that change. In this version it will the same configured field with a location per line to make maps with markers instead of just specifying the center.



Source Code with Markers change
/**

 * Copyright 2020 Bocoup

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to

 * deal in the Software without restriction, including without limitation the

 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

 * sell copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

 * IN THE SOFTWARE.

 */



/**

 * Airtable attach google static maps script

 *

 * This script looks at each row and adds google map images to an attachment

 * field cell in that row based on the addresses in the row. Rows with no

 * addresses or that already has attachments are skipped.

 *

 * This script uses Google's static map API. See for more info:

 * https://developers.google.com/maps/documentation/maps-static/intro

 *

 * **Notes on adapting this script.**

 *

 * Before running this script set the apiKey, tableName, addressFieldNames, and

 * mapTileAttachmentFieldName variables below. After that it can be run at any

 * time and it will update new records or old records with an empty attachments

 * cell. Further customizations can be made to the maps by modifying

 * staticmapOptions further down.

 */



'use strict';



// Google Maps API key

// See google's documentation to get a key.

// https://developers.google.com/maps/documentation/javascript/get-api-key

//

// The text of this script including the apiKey will be visible to everyone who

// can view this airtable base.

let apiKey = '**************';



// The name of the table this script will update.

let tableName = 'Map Table';

// Names of fields with an address to get a map for. Each field can have 0 or 1

// addresses.

let addressFieldNames = [

    'Map Address',

    // 'Start Address',

    // 'Special Address',

];

// Name of an attachments field that will be updated with static google map images.

let mapTileAttachmentFieldName = 'Map Attachments';



//

// After this line is the script logic. To use this script as-is, you do not need

// to edit anything after this point.

//



let RECORD_BATCH_COUNT = 50;



let table = base.getTable(tableName);

let allRecords = await table.selectRecordsAsync({

    // In the case there are a lot of fields, get the address and map tile fields only.

    fields: [...addressFieldNames, mapTileAttachmentFieldName],

});



let updates = [];



// Iterate every record in the table.

for (let recordId of allRecords.recordIds) {

    let record = allRecords.getRecord(recordId);



    // Skip records that have no addresses or already have attached images.

    if (

        !addressFieldNames.some(fieldName => record.getCellValue(fieldName)) ||

        record.getCellValue(mapTileAttachmentFieldName)

    ) {

        continue;

    }



    // Create google static map api urls from address fields for this record.

    let urls = [];

    for (let fieldName of addressFieldNames) {

        let staticmapOptions = {

            // The Google API Key. Required.

            key: apiKey,

            // Add markers to the map. This is a set of locations written as

            // coordinates or addresses. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

            markers: 'color:black|' + record.getCellValue(fieldName).split('\n').join('|'),

            // The center of the returned map. Can be latitude, longitude

            // coordinates or an address. Optional if markers is set.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Locations

            // center: '',

            // Smaller numbers zoom out, larger numbers zoom in. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Zoomlevels

            zoom: 17,



            // 640 by 640 pixels is the largest normal resolution at scale 1. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Largerimagesizes

            size: [640, 640],

            // Scale can be 1 or 2. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#scale_values

            scale: 1,

            // Which image format to return. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#ImageFormats

            format: 'jpg',

            // Maptype can be roadmap, terrain, hybrid, or streetview. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#MapTypes

            maptype: 'roadmap',

            // Language and region are optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#map-parameters

            language: 'en-US',

            region: 'us',



            // There are other options.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#feature-parameters

        };



        let staticmapParameters = Object.entries(staticmapOptions).map(([key, value]) => {

            if (key === 'size') {

                return `size=${value[0]}x${value[1]}`;

            }

            return `${key}=${encodeURIComponent(value)}`;

        });

        let staticmapUrl = `https://maps.googleapis.com/maps/api/staticmap?${staticmapParameters.join('&')}`;



        // Add a attachment cell object to urls to add to the record update.

        urls.push({url: staticmapUrl});

    }



    // Create record update with map urls.

    updates.push({id: record.id, fields: {[mapTileAttachmentFieldName]: urls}});

}



output.markdown(`Prepared ${updates.length} row updates out of ${allRecords.recordIds.length} in the table.`);



// For subsets of updates

for (let i = 0; i < updates.length; i += RECORD_BATCH_COUNT) {

    // Update table with a subset of all the updates ready to be made.

    output.markdown(`Applying update ${i + 1} through ${Math.min(i + RECORD_BATCH_COUNT, updates.length)} of ${updates.length}.`);

    await table.updateRecordsAsync(updates.slice(i, i + RECORD_BATCH_COUNT));

}



output.markdown('Done.');



Hey This is awsome thanks. I feel super powerfull!


I have just found the loc of 100 dreds of locations.


I’m now trying to adapt this so that I can run an automated script so that the image can be added to new records that come in with an address. So rather than finding a screenshot of all records with addresses I’m looking for A screenshot of the Address value I have brought in from the automation.


Sorry i imagine this is a super rookeie question I have no idea what I’m diong with Java but looks like I could get the hang of it someday :winking_face:


Thanks in advance,

Alfred


  • Participating Frequently
  • 8 replies
  • January 3, 2022
Z_Goddard wrote:

Hi @Melissa_Bradley,


You can change the script to add markers. One way to change it would be to replace center in the staticmapOptions object to markers with something like:



// Add markers to the map. This is a set of locations written as

// coordinates or addresses. Required.

// See for more info:

// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

markers: ‘color:black|’ + record.getCellValue(fieldName).split(’\n’).join(’|’),



Here is the full script edited with that change. In this version it will the same configured field with a location per line to make maps with markers instead of just specifying the center.



Source Code with Markers change
/**

 * Copyright 2020 Bocoup

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to

 * deal in the Software without restriction, including without limitation the

 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

 * sell copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

 * IN THE SOFTWARE.

 */



/**

 * Airtable attach google static maps script

 *

 * This script looks at each row and adds google map images to an attachment

 * field cell in that row based on the addresses in the row. Rows with no

 * addresses or that already has attachments are skipped.

 *

 * This script uses Google's static map API. See for more info:

 * https://developers.google.com/maps/documentation/maps-static/intro

 *

 * **Notes on adapting this script.**

 *

 * Before running this script set the apiKey, tableName, addressFieldNames, and

 * mapTileAttachmentFieldName variables below. After that it can be run at any

 * time and it will update new records or old records with an empty attachments

 * cell. Further customizations can be made to the maps by modifying

 * staticmapOptions further down.

 */



'use strict';



// Google Maps API key

// See google's documentation to get a key.

// https://developers.google.com/maps/documentation/javascript/get-api-key

//

// The text of this script including the apiKey will be visible to everyone who

// can view this airtable base.

let apiKey = '**************';



// The name of the table this script will update.

let tableName = 'Map Table';

// Names of fields with an address to get a map for. Each field can have 0 or 1

// addresses.

let addressFieldNames = [

    'Map Address',

    // 'Start Address',

    // 'Special Address',

];

// Name of an attachments field that will be updated with static google map images.

let mapTileAttachmentFieldName = 'Map Attachments';



//

// After this line is the script logic. To use this script as-is, you do not need

// to edit anything after this point.

//



let RECORD_BATCH_COUNT = 50;



let table = base.getTable(tableName);

let allRecords = await table.selectRecordsAsync({

    // In the case there are a lot of fields, get the address and map tile fields only.

    fields: [...addressFieldNames, mapTileAttachmentFieldName],

});



let updates = [];



// Iterate every record in the table.

for (let recordId of allRecords.recordIds) {

    let record = allRecords.getRecord(recordId);



    // Skip records that have no addresses or already have attached images.

    if (

        !addressFieldNames.some(fieldName => record.getCellValue(fieldName)) ||

        record.getCellValue(mapTileAttachmentFieldName)

    ) {

        continue;

    }



    // Create google static map api urls from address fields for this record.

    let urls = [];

    for (let fieldName of addressFieldNames) {

        let staticmapOptions = {

            // The Google API Key. Required.

            key: apiKey,

            // Add markers to the map. This is a set of locations written as

            // coordinates or addresses. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

            markers: 'color:black|' + record.getCellValue(fieldName).split('\n').join('|'),

            // The center of the returned map. Can be latitude, longitude

            // coordinates or an address. Optional if markers is set.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Locations

            // center: '',

            // Smaller numbers zoom out, larger numbers zoom in. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Zoomlevels

            zoom: 17,



            // 640 by 640 pixels is the largest normal resolution at scale 1. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Largerimagesizes

            size: [640, 640],

            // Scale can be 1 or 2. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#scale_values

            scale: 1,

            // Which image format to return. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#ImageFormats

            format: 'jpg',

            // Maptype can be roadmap, terrain, hybrid, or streetview. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#MapTypes

            maptype: 'roadmap',

            // Language and region are optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#map-parameters

            language: 'en-US',

            region: 'us',



            // There are other options.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#feature-parameters

        };



        let staticmapParameters = Object.entries(staticmapOptions).map(([key, value]) => {

            if (key === 'size') {

                return `size=${value[0]}x${value[1]}`;

            }

            return `${key}=${encodeURIComponent(value)}`;

        });

        let staticmapUrl = `https://maps.googleapis.com/maps/api/staticmap?${staticmapParameters.join('&')}`;



        // Add a attachment cell object to urls to add to the record update.

        urls.push({url: staticmapUrl});

    }



    // Create record update with map urls.

    updates.push({id: record.id, fields: {[mapTileAttachmentFieldName]: urls}});

}



output.markdown(`Prepared ${updates.length} row updates out of ${allRecords.recordIds.length} in the table.`);



// For subsets of updates

for (let i = 0; i < updates.length; i += RECORD_BATCH_COUNT) {

    // Update table with a subset of all the updates ready to be made.

    output.markdown(`Applying update ${i + 1} through ${Math.min(i + RECORD_BATCH_COUNT, updates.length)} of ${updates.length}.`);

    await table.updateRecordsAsync(updates.slice(i, i + RECORD_BATCH_COUNT));

}



output.markdown('Done.');



Can this work with the Embed Google Map API rather than the static map. Wondering also if you can map the URLs as well into a field


  • New Participant
  • 4 replies
  • September 9, 2022

I have been trying so hard to figure this out. The script “runs” fine but no attachment gets put in. I have tried with the full address as well as lat and long coordinates. I want just a static google map image to populate in the attachment field. My API and geo stuff on the google side is fine because this works fine in the Maps extension.


  • Known Participant
  • 13 replies
  • October 17, 2022
JJ_Francis wrote:

I have been trying so hard to figure this out. The script “runs” fine but no attachment gets put in. I have tried with the full address as well as lat and long coordinates. I want just a static google map image to populate in the attachment field. My API and geo stuff on the google side is fine because this works fine in the Maps extension.


did you ever figure this out? I’m having the same problem


  • Known Participant
  • 13 replies
  • October 17, 2022

The script “runs” fine but no attachment gets put in. My API works in the Maps extension. Trying to set up a script to run based on an automation.


  • Participating Frequently
  • 7 replies
  • December 8, 2023
Z_Goddard wrote:

Hi @Melissa_Bradley,


You can change the script to add markers. One way to change it would be to replace center in the staticmapOptions object to markers with something like:



// Add markers to the map. This is a set of locations written as

// coordinates or addresses. Required.

// See for more info:

// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

markers: ‘color:black|’ + record.getCellValue(fieldName).split(’\n’).join(’|’),



Here is the full script edited with that change. In this version it will the same configured field with a location per line to make maps with markers instead of just specifying the center.



Source Code with Markers change
/**

 * Copyright 2020 Bocoup

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to

 * deal in the Software without restriction, including without limitation the

 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or

 * sell copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

 * IN THE SOFTWARE.

 */



/**

 * Airtable attach google static maps script

 *

 * This script looks at each row and adds google map images to an attachment

 * field cell in that row based on the addresses in the row. Rows with no

 * addresses or that already has attachments are skipped.

 *

 * This script uses Google's static map API. See for more info:

 * https://developers.google.com/maps/documentation/maps-static/intro

 *

 * **Notes on adapting this script.**

 *

 * Before running this script set the apiKey, tableName, addressFieldNames, and

 * mapTileAttachmentFieldName variables below. After that it can be run at any

 * time and it will update new records or old records with an empty attachments

 * cell. Further customizations can be made to the maps by modifying

 * staticmapOptions further down.

 */



'use strict';



// Google Maps API key

// See google's documentation to get a key.

// https://developers.google.com/maps/documentation/javascript/get-api-key

//

// The text of this script including the apiKey will be visible to everyone who

// can view this airtable base.

let apiKey = '**************';



// The name of the table this script will update.

let tableName = 'Map Table';

// Names of fields with an address to get a map for. Each field can have 0 or 1

// addresses.

let addressFieldNames = [

    'Map Address',

    // 'Start Address',

    // 'Special Address',

];

// Name of an attachments field that will be updated with static google map images.

let mapTileAttachmentFieldName = 'Map Attachments';



//

// After this line is the script logic. To use this script as-is, you do not need

// to edit anything after this point.

//



let RECORD_BATCH_COUNT = 50;



let table = base.getTable(tableName);

let allRecords = await table.selectRecordsAsync({

    // In the case there are a lot of fields, get the address and map tile fields only.

    fields: [...addressFieldNames, mapTileAttachmentFieldName],

});



let updates = [];



// Iterate every record in the table.

for (let recordId of allRecords.recordIds) {

    let record = allRecords.getRecord(recordId);



    // Skip records that have no addresses or already have attached images.

    if (

        !addressFieldNames.some(fieldName => record.getCellValue(fieldName)) ||

        record.getCellValue(mapTileAttachmentFieldName)

    ) {

        continue;

    }



    // Create google static map api urls from address fields for this record.

    let urls = [];

    for (let fieldName of addressFieldNames) {

        let staticmapOptions = {

            // The Google API Key. Required.

            key: apiKey,

            // Add markers to the map. This is a set of locations written as

            // coordinates or addresses. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers

            markers: 'color:black|' + record.getCellValue(fieldName).split('\n').join('|'),

            // The center of the returned map. Can be latitude, longitude

            // coordinates or an address. Optional if markers is set.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Locations

            // center: '',

            // Smaller numbers zoom out, larger numbers zoom in. Required.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Zoomlevels

            zoom: 17,



            // 640 by 640 pixels is the largest normal resolution at scale 1. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Imagesizes

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#Largerimagesizes

            size: [640, 640],

            // Scale can be 1 or 2. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#scale_values

            scale: 1,

            // Which image format to return. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#ImageFormats

            format: 'jpg',

            // Maptype can be roadmap, terrain, hybrid, or streetview. Optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#MapTypes

            maptype: 'roadmap',

            // Language and region are optional.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#map-parameters

            language: 'en-US',

            region: 'us',



            // There are other options.

            // See for more info:

            // https://developers.google.com/maps/documentation/maps-static/dev-guide#feature-parameters

        };



        let staticmapParameters = Object.entries(staticmapOptions).map(([key, value]) => {

            if (key === 'size') {

                return `size=${value[0]}x${value[1]}`;

            }

            return `${key}=${encodeURIComponent(value)}`;

        });

        let staticmapUrl = `https://maps.googleapis.com/maps/api/staticmap?${staticmapParameters.join('&')}`;



        // Add a attachment cell object to urls to add to the record update.

        urls.push({url: staticmapUrl});

    }



    // Create record update with map urls.

    updates.push({id: record.id, fields: {[mapTileAttachmentFieldName]: urls}});

}



output.markdown(`Prepared ${updates.length} row updates out of ${allRecords.recordIds.length} in the table.`);



// For subsets of updates

for (let i = 0; i < updates.length; i += RECORD_BATCH_COUNT) {

    // Update table with a subset of all the updates ready to be made.

    output.markdown(`Applying update ${i + 1} through ${Math.min(i + RECORD_BATCH_COUNT, updates.length)} of ${updates.length}.`);

    await table.updateRecordsAsync(updates.slice(i, i + RECORD_BATCH_COUNT));

}



output.markdown('Done.');



This is  really helpful script, thank you!

I keep getting an error when trying to do this Marker Mod and replace center. Im not that familiar with Javascript so probably missing something fairly obvious

 

Error

SyntaxError: illegal character U+2018
    at u/< on line 1    at E on line 1    at _/< on line 1    at m/</< on line 1    at r on line 1    at a on line 1    at n/</< on line 1    at n/< on line 1    at ai on line 1    at Di on line 1    at u/< on line 1    at E on line 1    at _/< on line 1    at m/</< on line 1    at r on line 1    at a on line 1    at n/</< on line 1    at n/< on line 1    at si< on line 1    at r/< on line 1    at E on line 1    at _/< on line 1    at m/</< on line 1    at r on line 1    at a on line 1    at n/</< on line 1    at n/< on line 1    at _handleCallAsync on line 1    at handle on line 1    on line 1

  • Participating Frequently
  • 7 replies
  • December 8, 2023
rp2 wrote:

This is  really helpful script, thank you!

I keep getting an error when trying to do this Marker Mod and replace center. Im not that familiar with Javascript so probably missing something fairly obvious

 

Error

SyntaxError: illegal character U+2018
    at u/< on line 1    at E on line 1    at _/< on line 1    at m/</< on line 1    at r on line 1    at a on line 1    at n/</< on line 1    at n/< on line 1    at ai on line 1    at Di on line 1    at u/< on line 1    at E on line 1    at _/< on line 1    at m/</< on line 1    at r on line 1    at a on line 1    at n/</< on line 1    at n/< on line 1    at si< on line 1    at r/< on line 1    at E on line 1    at _/< on line 1    at m/</< on line 1    at r on line 1    at a on line 1    at n/</< on line 1    at n/< on line 1    at _handleCallAsync on line 1    at handle on line 1    on line 1

Error was the way the single quotes pasted in. I had to retype those for some reason. works great!👍