> For the complete documentation index, see [llms.txt](https://docs.csvgetter.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.csvgetter.com/google-apps-script-integration.md).

# Google Apps Script Integration

### Quick Start

#### Step 1: Open the Script Editor

1. Open your Google Sheet.
2. Go to **Extensions > Apps Script**.
3. Delete any existing code in the editor.

#### Step 2: Paste the Script

```javascript
/**
 * Fetches data from CSV Getter and writes it to the active sheet.
 * Replace ENDPOINT_URL with your actual CSV Getter endpoint URL.
 */

// ========== CONFIGURATION ==========
var ENDPOINT_URL = "https://api.csvgetter.com/YOUR_ENDPOINT_ID";
var SHEET_NAME = "Sheet1";                    // Target sheet tab name
var BEARER_TOKEN = "";                        // Leave empty if auth is not enabled
var NOTIFY_EMAIL = "";                        // Email for failure alerts (leave empty to skip)
// ====================================

function fetchCSVGetterData() {
  try {
    var options = {};

    // Add auth header if Bearer token is set
    if (BEARER_TOKEN) {
      options = {
        headers: {
          "Authorization": "Bearer " + BEARER_TOKEN
        }
      };
    }

    // Fetch data from CSV Getter
    var response = UrlFetchApp.fetch(ENDPOINT_URL, options);
    var statusCode = response.getResponseCode();

    if (statusCode !== 200) {
      var errorMsg = "CSV Getter returned status " + statusCode + ": " + response.getContentText();
      Logger.log(errorMsg);
      sendFailureAlert(errorMsg);
      return;
    }

    var csvContent = response.getContentText();

    if (!csvContent || csvContent.trim() === "") {
      var emptyMsg = "CSV Getter returned empty data.";
      Logger.log(emptyMsg);
      sendFailureAlert(emptyMsg);
      return;
    }

    // Parse CSV into rows
    var rows = Utilities.parseCsv(csvContent);

    // Get the target sheet
    var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = spreadsheet.getSheetByName(SHEET_NAME);

    if (!sheet) {
      sheet = spreadsheet.insertSheet(SHEET_NAME);
    }

    // Clear existing data and write new data
    sheet.clearContents();
    sheet.getRange(1, 1, rows.length, rows[0].length).setValues(rows);

    Logger.log("Successfully imported " + rows.length + " rows (including header) at " + new Date().toISOString());

  } catch (error) {
    var errMsg = "Error fetching CSV Getter data: " + error.message;
    Logger.log(errMsg);
    sendFailureAlert(errMsg);
  }
}

/**
 * Sends an email alert when the import fails.
 */
function sendFailureAlert(errorMessage) {
  if (!NOTIFY_EMAIL) return;

  try {
    var subject = "CSV Getter Import Failed - " + SpreadsheetApp.getActiveSpreadsheet().getName();
    var body = "The scheduled CSV Getter import failed.\n\n" +
               "Spreadsheet: " + SpreadsheetApp.getActiveSpreadsheet().getUrl() + "\n" +
               "Sheet: " + SHEET_NAME + "\n" +
               "Endpoint: " + ENDPOINT_URL + "\n" +
               "Time: " + new Date().toISOString() + "\n\n" +
               "Error: " + errorMessage + "\n\n" +
               "Please check your endpoint at https://csvgetter.com";

    MailApp.sendEmail(NOTIFY_EMAIL, subject, body);
    Logger.log("Failure alert sent to " + NOTIFY_EMAIL);
  } catch (e) {
    Logger.log("Could not send failure alert email: " + e.message);
  }
}
```

#### Step 3: Configure

1. Replace `YOUR_ENDPOINT_ID` with your actual endpoint ID.
2. Set `SHEET_NAME` to the tab name where data should be written.
3. If your endpoint has auth enabled, set `BEARER_TOKEN` to your token.
4. (Optional) Set `NOTIFY_EMAIL` to receive alerts on failure.

#### Step 4: Test

1. Click the **Run** button (play icon) at the top.
2. The first time, Google will ask you to authorize the script. Click **Review Permissions** > **Allow**.
3. Check your Google Sheet — the data should appear.
4. Check **Execution log** (View > Execution log) for success/error messages.

***

### Setting Up a Time-Driven Trigger

To run the import automatically on a schedule:

#### Option A: Via the Apps Script UI

1. In the Apps Script editor, click the **Triggers** icon (clock icon) in the left sidebar.
2. Click **+ Add Trigger**.
3. Configure:
   * **Function:** `fetchCSVGetterData`
   * **Deployment:** Head
   * **Event source:** Time-driven
   * **Type of time-based trigger:** Choose one:
     * **Minutes timer** — Every 5, 10, 15, or 30 minutes
     * **Hour timer** — Every 1, 2, 4, 6, 8, or 12 hours
     * **Day timer** — Once per day (pick the time window)
     * **Week timer** — Once per week (pick day and time)
4. Click **Save**.

#### Option B: Via Code

Add this function to your script and run it once to create the trigger:

```javascript
/**
 * Creates a time-driven trigger. Run this function ONCE to set up the schedule.
 */
function createDailyTrigger() {
  // Delete any existing triggers for this function to avoid duplicates
  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {
    if (triggers[i].getHandlerFunction() === "fetchCSVGetterData") {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }

  // Create a new daily trigger at 8:00-9:00 AM
  ScriptApp.newTrigger("fetchCSVGetterData")
    .timeBased()
    .everyDays(1)
    .atHour(8)
    .create();

  Logger.log("Daily trigger created.");
}
```

Other schedule options:

```javascript
// Every hour
ScriptApp.newTrigger("fetchCSVGetterData")
  .timeBased()
  .everyHours(1)
  .create();

// Every 30 minutes
ScriptApp.newTrigger("fetchCSVGetterData")
  .timeBased()
  .everyMinutes(30)
  .create();

// Every Monday at 9 AM
ScriptApp.newTrigger("fetchCSVGetterData")
  .timeBased()
  .onWeekDay(ScriptApp.WeekDay.MONDAY)
  .atHour(9)
  .create();
```

***

### Importing JSON Instead of CSV

If you prefer JSON (e.g., for more control over parsing):

```javascript
function fetchCSVGetterDataAsJSON() {
  try {
    var url = ENDPOINT_URL + "?type=json_records";
    var options = {};

    if (BEARER_TOKEN) {
      options = {
        headers: { "Authorization": "Bearer " + BEARER_TOKEN }
      };
    }

    var response = UrlFetchApp.fetch(url, options);

    if (response.getResponseCode() !== 200) {
      sendFailureAlert("Status " + response.getResponseCode() + ": " + response.getContentText());
      return;
    }

    var data = JSON.parse(response.getContentText());

    if (!data || data.length === 0) {
      sendFailureAlert("No data returned.");
      return;
    }

    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
    if (!sheet) {
      sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(SHEET_NAME);
    }

    // Write headers from first object's keys
    var headers = Object.keys(data[0]);
    sheet.clearContents();
    sheet.getRange(1, 1, 1, headers.length).setValues([headers]);

    // Write data rows
    var rows = data.map(function(record) {
      return headers.map(function(header) {
        var value = record[header];
        return value !== null && value !== undefined ? value : "";
      });
    });

    if (rows.length > 0) {
      sheet.getRange(2, 1, rows.length, headers.length).setValues(rows);
    }

    Logger.log("Imported " + rows.length + " records.");

  } catch (error) {
    sendFailureAlert(error.message);
  }
}
```

***

### Using SQL Filters

Add SQL to the URL to only import filtered data:

```javascript
var ENDPOINT_URL = "https://api.csvgetter.com/YOUR_ENDPOINT_ID?sql=" +
  encodeURIComponent("SELECT name, email, status FROM csvgetter WHERE status = 'Active' ORDER BY name");
```

***

### Credit Usage

Each time the script runs and hits the endpoint, it uses 1 credit. Plan your trigger frequency accordingly:

| Frequency     | Credits/Month |
| ------------- | ------------- |
| Every 30 min  | \~1,440       |
| Every hour    | \~720         |
| Every 6 hours | \~120         |
| Daily         | \~30          |
| Weekly        | \~4           |

***

### Troubleshooting

| Issue                             | Cause                                             | Fix                                         |
| --------------------------------- | ------------------------------------------------- | ------------------------------------------- |
| `Exception: Request failed`       | Endpoint URL is wrong or server is down           | Verify the URL works in a browser first     |
| `401 Unauthorized`                | Bearer token is missing or wrong                  | Check `BEARER_TOKEN` value                  |
| `403 Forbidden`                   | Out of credits                                    | Purchase credits at csvgetter.com           |
| `Exceeded maximum execution time` | Dataset too large for Apps Script timeout (6 min) | Add `sql=...LIMIT 5000` to reduce data size |
| Script runs but sheet is empty    | Wrong `SHEET_NAME`                                | Check the tab name matches exactly          |
| Trigger not firing                | Trigger wasn't saved or was deleted               | Re-create the trigger in the Triggers panel |
