getValues() gives you what's stored in the cell: a Date object, 0.125, 4500. Sometimes you want what the cell shows: Dec 18, 2026, 12.5%, $4,500.00. getDisplayRowObjects(sheet, opts) reads the sheet with getDisplayValues() and turns each row into an object keyed by header, with the header row configurable. Every value is a string, formatted exactly as on screen.
When to use
- Emails and PDFs that should match what people see in the sheet
- Exports where
4500must stay$4,500.00 - Prompts and logs where a readable date beats
Thu Dec 18 2026 00:00:00 GMT-0500
Need the real values for math? Use rowsToObjects. Need only the rows a filter is showing? Use getVisibleRowObjects.
How to use this snippet
/**
* Rows as objects using the values the cells DISPLAY (all strings).
*
* @param {Sheet=} sheet default: active sheet
* @param {Object=} opts { headerRow: 1, includeRowNumber: true, skipBlank: true }
* @return {Object[]} each { header: displayValue, ..., _row: n }
*/
function getDisplayRowObjects(sheet, opts) {
sheet = sheet || SpreadsheetApp.getActiveSheet();
opts = opts || {};
var headerRow = opts.headerRow || 1;
var lastRow = sheet.getLastRow(), lastCol = sheet.getLastColumn();
if (lastRow <= headerRow || !lastCol) return [];
var headers = sheet.getRange(headerRow, 1, 1, lastCol).getDisplayValues()[0];
var rows = sheet.getRange(headerRow + 1, 1, lastRow - headerRow, lastCol).getDisplayValues();
var out = [];
rows.forEach(function (r, i) {
if (opts.skipBlank !== false && r.join('') === '') return;
var o = {};
headers.forEach(function (h, c) { if (h) o[h] = r[c]; });
if (opts.includeRowNumber !== false) o._row = headerRow + 1 + i;
out.push(o);
});
return out;
}
Example
function emailInvoiceSummary() {
var sh = SpreadsheetApp.getActive().getSheetByName('Invoices');
var rows = getDisplayRowObjects(sh, { headerRow: 2 }); // title in row 1
var body = rows.map(function (r) {
return r['Client'] + ': ' + r['Amount'] + ' due ' + r['Due Date'];
}).join('\n');
MailApp.sendEmail(Session.getEffectiveUser().getEmail(), 'Open invoices', body);
}
// Acme Ltd: $4,500.00 due Dec 18, 2026
Tips:
- Every value is a string. Don't add them up:
'$4,500.00' + '$10.00'is not a total. - Display values depend on the cell format and the spreadsheet locale, so a format change changes your output.
- Mix the two when you need both: read numbers with
getValues(), labels withgetDisplayValues(), from the same range.
Tip: NitroGAS Co-Pilot can switch an email or export builder to display values while keeping the math on real values. Paste the function.
Happy Coding!
