Help

Re: Add google static maps to an attachments field

4404 0
cancel
Showing results for 
Search instead for 
Did you mean: 
Z_Goddard
5 - Automation Enthusiast
5 - Automation Enthusiast

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 22
Aron
7 - App Architect
7 - App Architect

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

Eddie_Kaeser
6 - Interface Innovator
6 - Interface Innovator

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?

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

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.

Melissa_Bradley
6 - Interface Innovator
6 - Interface Innovator

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.

@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.');

This worked great!! Thank you so much!

Ed_Moore
5 - Automation Enthusiast
5 - Automation Enthusiast

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 :slightly_smiling_face:

This video could interested you

Thibaud_Donzier
6 - Interface Innovator
6 - Interface Innovator

Hi everyone,

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

Thanks in advance :slightly_smiling_face:

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

Casey_Reid
5 - Automation Enthusiast
5 - Automation Enthusiast

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

NH_Airtable
4 - Data Explorer
4 - Data Explorer

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?

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 Screenshot 2021-10-27 at 22.14.40

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

JJ_Francis
5 - Automation Enthusiast
5 - Automation Enthusiast

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