Analyze your CSV files in Google Sheets
If you’d like to use Google Sheets functions such as QUERY(), FILTER(), or REGEXMATCH() to search and analyze the CSV files produced by the AppSheet Parser Suite, this script can save you a lot of manual work.
Why It’s Useful
AppSheet’s HTML export, once parsed by the Parser Suite, produces several CSVs (appsheet_columns.csv, appsheet_views.csv, etc.).
Analyzing relationships or searching across them inside Google Sheets can be powerful, but importing each file by hand is tedious and error-prone.
This Google Apps Script automatically creates a Google Sheets file containing the parsed data from your app. Expressions are brought into the file as text to prevent errors and ensure that they will be searchable. Once converted to a Google Sheets file, you can use spreadsheet tools (QUERY, FILTER, BYROW, etc.) to explore your app.
Preparation
Before running the script, upload your parsed CSV files to Google Drive:
- Locate the folder on your computer that contains the CSV files produced by the AppSheet Parser Suite.
- Open https://drive.google.com in your browser.
- Drag and drop that folder into Google Drive.
- Drive will upload the entire folder and preserve its name.
- After the upload finishes, open the folder in Drive.
- Copy the URL from your browser’s address bar — it should look like this:
https://drive.google.com/drive/folders/1A2b3C4D5E6F7G8H9I0J
- Before you run the script, you’ll need to paste this URL into it, replacing the placeholder text inside this line:
const folderInput = "PASTE_YOUR_FOLDER_URL_OR_ID_HERE";
Script
// --- begin script ---
/**
* Import all CSV files from a Google Drive folder into one spreadsheet.
* - Spreadsheet name = folder name (exactly)
* - Sheet names = CSV file names (without .csv)
* - All values imported as literal text
* - Result link shown in Execution Log
*/
function importCSVsFromFolderDirect() {
const folderInput = "PASTE_YOUR_FOLDER_URL_OR_ID_HERE";
const folderId = extractFolderId(folderInput);
if (!folderId) {
Logger.log("❌ Invalid folder URL or ID. Please check the line near the top of the script.");
return;
}
const link = importCSVsFromFolder(folderId);
Logger.log("✅ Done! Created spreadsheet: " + link);
}
function importCSVsFromFolder(folderId) {
const folder = DriveApp.getFolderById(folderId);
const folderName = folder.getName();
const ss = SpreadsheetApp.create(folderName);
const files = folder.getFiles();
let csvCount = 0;
while (files.hasNext()) {
const file = files.next();
const name = file.getName();
if (!/\.csv$/i.test(name)) continue;
const text = stripBOM(file.getBlob().getDataAsString('UTF-8'));
const delimiter = detectDelimiter(text);
const rows = Utilities.parseCsv(text, delimiter) || [];
// Treat all cells as literal text
const safeRows = rows.map(row =>
row.map(cell => {
let value = String(cell);
if (/^[=+]/.test(value)) value = "'" + value; // escape formulas
return value;
})
);
const sheetName = makeUniqueSheetName(ss, sanitizeSheetName(name.replace(/\.csv$/i, '')));
const sheet = ss.insertSheet(sheetName);
const range = sheet.getRange(1, 1, Math.max(1, safeRows.length), Math.max(1, safeRows[0]?.length || 1));
range.setNumberFormat('@');
if (safeRows.length > 0 && safeRows[0].length > 0) {
range.setValues(safeRows);
}
csvCount++;
}
const defaultSheet = ss.getSheets()[0];
if (defaultSheet.getDataRange().getValue() === '') ss.deleteSheet(defaultSheet);
if (csvCount === 0) Logger.log("⚠️ No CSV files found in this folder.");
return ss.getUrl();
}
/** ---------- Helpers ---------- **/
function extractFolderId(input) {
const urlMatch = input.match(/\/folders\/([a-zA-Z0-9_-]+)/);
if (urlMatch) return urlMatch[1];
const qMatch = input.match(/[?&]id=([a-zA-Z0-9_-]+)/);
if (qMatch) return qMatch[1];
if (/^[a-zA-Z0-9_-]{20,}$/.test(input)) return input;
return null;
}
function stripBOM(text) {
return text.charCodeAt(0) === 0xFEFF ? text.slice(1) : text;
}
function detectDelimiter(text) {
const firstLine = (text.split(/\r?\n/).find(l => l.trim().length) || '');
const counts = { ',': (firstLine.match(/,/g) || []).length, '\t': (firstLine.match(/\t/g) || []).length, ';': (firstLine.match(/;/g) || []).length };
let best = ',', max = -1;
for (const d in counts) if (counts[d] > max) { max = counts[d]; best = d; }
return best;
}
function sanitizeSheetName(name) {
let n = name.replace(/[\[\]\:\*\?\/\\]/g, ' ');
if (n.length > 100) n = n.slice(0, 100);
return n.trim() || 'Sheet';
}
function makeUniqueSheetName(ss, base) {
let name = base, i = 2;
while (ss.getSheetByName(name)) {
const suffix = ' (' + i + ')';
const head = base.length + suffix.length > 100 ? base.slice(0, 100 - suffix.length) : base;
name = head + suffix;
i++;
}
return name;
}
// --- end script ---
How to Use
- Open https://script.google.com and click New project.
- Delete any placeholder code and paste the complete script above.
- Click
Save, then give the project a name such as CSV Folder Importer.
- At the top of the script, find this line:
const folderInput = "PASTE_YOUR_FOLDER_URL_OR_ID_HERE";
Paste your Google Drive folder URL or ID between the quotes.
- Example:
https://drive.google.com/drive/folders/1A2b3C4D5E6F7G8H9I0J
- From the function dropdown, choose
importCSVsFromFolderDirect, then click the
Run button.
- The first time you run it, you’ll be asked to authorize access to your Google Drive and Sheets.
- After it finishes, open the Execution log:
- Click the link. You’ll find:
- A new Google Sheet named exactly like your Drive folder
- One tab for each CSV file in that folder
- All content imported as plain text (no formulas or dates converted)
Next Steps
Once you have the combined Google Sheet, you can use spreadsheet formulas to explore your AppSheet data.
Tip: Once you’ve verified that everything imports correctly, you can reuse this script anytime—just change the folder URL near the top and run it again to generate a fresh Google Sheet for new projects or new versions of the same project.
P.S. To save time, I used ChatGPT to prepare this post and the script. I have confirmed that the script works with my own data and I have read and revised the text of this post to my satisfaction. Any remaining problems are my fault, of course, not the responsibility of any AI tool I used.