Can anyone fix this TinyPNG script for our non-profit?

Topic Labels: Scripts TinyPNG
3517 2
Showing results for 
Search instead for 
Did you mean: 
4 - Data Explorer
4 - Data Explorer

Hey Airtable community

We're a 100% volunteer non profit organization, using Airtable to handle events where we match street artists with underserved communities and local organizers. That means dealing with a lot of images and we're maxing out the 20GB in our Pro plan. 

With inspiration from John Siciliano's post where he build an image compressor with TinyPng for a single image, I wanted to extend it a bit. A friend tried to add:

  • multi-image iteration,
  • renaming,
  • image resizing
  • move PDF's to a different cell in the record

and got something put together on top of John's script. However, when it runs, it keeps looping through logs "compress null" and "TinyPNG API failed with status code: 400 and message: Bad Request"

He's a bit excessive with his let-variables, but I don't see that being the cause. Can anyone help make the script run properly? Any help will be appreciated.


let tinyPngApiKey = 'api_key_removed';
let airtableAttachmentSource = 'artwork';
let airtableAttachmentDestination = 'compressed_downsized_artwork';
let airtableColumnToLog = 'image_log';

let airtableColumnToLogCountry = 'artist_name_and_country';
let airtableColumnToLogCV = 'artist_pdf';
let currentYear = new Date().getFullYear();
let counter = 1;
let maximumWidth = 1080;
let maximumHeight = 1080;

let table = base.getTable(cursor.activeTableId);
let view = table.getView(cursor.activeViewId);
let queryResult = await view.selectRecordsAsync();

for (let record of queryResult.records) {
  let recordAttachments = record.getCellValue(airtableAttachmentSource);
  let artistCountry = record.getCellValue(airtableColumnToLogCountry);
  let artistCV = record.getCellValue(airtableColumnToLogCV);
  for (let attachment of recordAttachments) {
    let attachmentUrl = attachment.url;
    let attachmentName = attachment.filename;
    let extension = attachmentName.split(".")[1];

    if (extension === "pdf"){
    } else {
    console.log('Compressing ' + record.getCellValue(airtableColumnToLog))
    let request = await remoteFetchAsync('', {
      method: 'POST',
      headers: {
        'Authorization': 'Basic ' + btoa('api:' + tinyPngApiKey),
        'Content-Type': 'application/json'
      body: JSON.stringify({'source': {'url': attachmentUrl}, 'resize': {'method': 'fit', 'width': maximumWidth, 'height': maximumHeight}})
    if (request.status !== 201) {
        console.log("TinyPNG API failed with status code: " + request.status + " and message: " + request.statusText);
    let compressed = await request.blob();
    let newName = `${artistCountry}_${currentYear}_${counter}.${extension}`;

    await table.updateRecordAsync(, {
      [airtableAttachmentDestination]: [{url: attachmentUrl, filename: newName}],
      [airtableColumnToLogCV]: artistCV


2 Replies 2

Hey @Streetstudies

I'm unfamiliar with TinyPNG, so I can't offer immediate help on the script itself. Still, I wanted to call out a workaround for you and your organization, specifically since you're knocking on the door of scalability issues if y'all are going to remain Pro for the foreseeable future.

It would be worth investing the development time into having Airtable push your attachments into an S3 or Google Cloud Storage bucket and then rely on Airtable to pseudo-index them after deleting the Airtable-hosted attachments.

This will ensure that you never have to worry about attachment limits.

Some more thoughts about using Airtable and attachment limits ...

  • Attachments can count towards your attachment limit even after they have been deleted. This is so that attachments can be restored from the trash, snapshots, etc.
  • This script will not gracefully handle records that do not have any attachments in them.
  • This script doesn't appear to actually do anything with the compressed result. It seems to move the original attachment from one field to another and rename the attachment, but the new field has the same uncompressed image, just with a new name.
  • If you want a small version of the image, you could replace an image with one of the Airtable generated thumbnails that is available via scripting.