Package Exports
- capacitor-google-sheets-zeattacker
- capacitor-google-sheets-zeattacker/dist/esm/index.js
- capacitor-google-sheets-zeattacker/dist/plugin.cjs.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (capacitor-google-sheets-zeattacker) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@zeattacker/capacitor-google-sheets
Capacitor plugin for Google Sheets REST API with support for Web (PWA), iOS, and Android platforms.
Features
- ✅ Cross-platform - Works on Web, iOS, and Android
- ✅ Type-safe - Full TypeScript support with detailed type definitions
- ✅ REST API - Uses Google Sheets REST API (no gapi library needed)
- ✅ Offline-compatible - Uses native fetch/URLSession/OkHttp
- ✅ Integrated - Works seamlessly with
@zeattacker/capacitor-google-auth - ✅ Complete - All major Sheets operations supported
Installation
npm install @zeattacker/capacitor-google-sheets
npx cap syncPrerequisites
This plugin requires @zeattacker/capacitor-google-auth for authentication:
npm install @zeattacker/capacitor-google-authRequired Scopes
Add the Google Sheets scope when initializing GoogleAuth:
import { GoogleAuth } from '@zeattacker/capacitor-google-auth';
await GoogleAuth.initialize({
clientId: 'YOUR_CLIENT_ID',
scopes: [
'profile',
'email',
'https://www.googleapis.com/auth/spreadsheets', // Full access
// OR
'https://www.googleapis.com/auth/drive.file' // App-created files only
]
});Scope options:
https://www.googleapis.com/auth/spreadsheets- Read and write access to all spreadsheetshttps://www.googleapis.com/auth/drive.file- Access only to files created by this app (recommended for privacy)
Quick Start
import { GoogleAuth } from '@zeattacker/capacitor-google-auth';
import { GoogleSheets } from '@zeattacker/capacitor-google-sheets';
// 1. Sign in with Google
await GoogleAuth.signIn();
// 2. Create a new spreadsheet
const spreadsheet = await GoogleSheets.createSpreadsheet({
title: 'My Finance Data',
sheets: [
{ title: 'Transactions', frozenRowCount: 1 },
{ title: 'Categories', frozenRowCount: 1 }
]
});
console.log('Created spreadsheet:', spreadsheet.spreadsheetUrl);
// 3. Write headers
await GoogleSheets.updateRange({
spreadsheetId: spreadsheet.spreadsheetId,
range: 'Transactions!A1:D1',
values: [['Date', 'Description', 'Amount', 'Category']]
});
// 4. Append data
await GoogleSheets.appendRows({
spreadsheetId: spreadsheet.spreadsheetId,
range: 'Transactions!A:D',
values: [
['2025-01-01', 'Coffee', '5.50', 'Food'],
['2025-01-02', 'Salary', '5000.00', 'Income']
]
});
// 5. Read data back
const data = await GoogleSheets.readRange({
spreadsheetId: spreadsheet.spreadsheetId,
range: 'Transactions!A:D'
});
console.log('Read data:', data.values);API Reference
createSpreadsheet()
Create a new Google Spreadsheet.
const result = await GoogleSheets.createSpreadsheet({
title: 'My Spreadsheet',
sheets: [
{
title: 'Sheet1',
frozenRowCount: 1, // Optional: freeze header row
frozenColumnCount: 0 // Optional: freeze columns
}
]
});
// Returns: SpreadsheetResult
// {
// spreadsheetId: string,
// title: string,
// spreadsheetUrl: string,
// sheets: Array<{ sheetId, title, index, ... }>
// }getSpreadsheet()
Get spreadsheet metadata.
const info = await GoogleSheets.getSpreadsheet({
spreadsheetId: 'abc123',
includeGridData: false // Optional: include cell values
});readRange()
Read values from a range.
const data = await GoogleSheets.readRange({
spreadsheetId: 'abc123',
range: 'Sheet1!A1:D10',
valueRenderOption: 'FORMATTED_VALUE', // Optional
dateTimeRenderOption: 'SERIAL_NUMBER' // Optional
});
// Returns: ValuesResult
// {
// range: string,
// values: (string | number | boolean)[][],
// rowCount: number,
// columnCount: number
// }Range formats:
'Sheet1!A1:D10'- Specific range'Sheet1!A:D'- Entire columns A through D'Sheet1'- Entire sheet
updateRange()
Update values in a range.
const result = await GoogleSheets.updateRange({
spreadsheetId: 'abc123',
range: 'Sheet1!A1:B2',
values: [
['Header1', 'Header2'],
['Value1', 'Value2']
],
valueInputOption: 'USER_ENTERED' // Optional: 'RAW' or 'USER_ENTERED'
});
// Returns: UpdateResult
// {
// updatedRange: string,
// updatedRows: number,
// updatedColumns: number,
// updatedCells: number
// }appendRows()
Append rows to the end of a sheet.
const result = await GoogleSheets.appendRows({
spreadsheetId: 'abc123',
range: 'Sheet1!A:D', // Or just 'Sheet1'
values: [
['Row1Col1', 'Row1Col2', 'Row1Col3', 'Row1Col4'],
['Row2Col1', 'Row2Col2', 'Row2Col3', 'Row2Col4']
],
valueInputOption: 'USER_ENTERED', // Optional
insertDataOption: 'INSERT_ROWS' // Optional: 'OVERWRITE' or 'INSERT_ROWS'
});clearRange()
Clear values in a range.
await GoogleSheets.clearRange({
spreadsheetId: 'abc123',
range: 'Sheet1!A2:Z100' // Clear data rows, keep headers
});batchUpdate()
Update multiple ranges at once.
const result = await GoogleSheets.batchUpdate({
spreadsheetId: 'abc123',
data: [
{
range: 'Sheet1!A1:B1',
values: [['Header1', 'Header2']]
},
{
range: 'Sheet2!A1:C1',
values: [['Col1', 'Col2', 'Col3']]
}
],
valueInputOption: 'USER_ENTERED' // Optional
});
// Returns: BatchUpdateResult
// {
// totalUpdatedCells: number,
// totalUpdatedRows: number,
// totalUpdatedColumns: number,
// totalUpdatedSheets: number
// }validateSheets()
Check if required sheets exist in a spreadsheet.
const validation = await GoogleSheets.validateSheets({
spreadsheetId: 'abc123',
requiredSheets: ['Transactions', 'Categories', 'Assets']
});
if (!validation.valid) {
console.log('Missing sheets:', validation.missing);
// Missing sheets: ['Assets']
}
// Returns: ValidationResult
// {
// valid: boolean,
// missing: string[],
// existing: string[]
// }Common Patterns
Initialize Headers on New Spreadsheet
const spreadsheet = await GoogleSheets.createSpreadsheet({
title: 'Finance Tracker',
sheets: [
{ title: 'Transactions', frozenRowCount: 1 },
{ title: 'Categories', frozenRowCount: 1 }
]
});
await GoogleSheets.batchUpdate({
spreadsheetId: spreadsheet.spreadsheetId,
data: [
{
range: 'Transactions!A1:E1',
values: [['Date', 'Description', 'Amount', 'Category', 'Notes']]
},
{
range: 'Categories!A1:B1',
values: [['Name', 'Type']]
}
]
});Find or Create Spreadsheet
async function getOrCreateSpreadsheet(): Promise<string> {
// Check localStorage for existing ID
const storedId = localStorage.getItem('my_spreadsheet_id');
if (storedId) {
try {
// Validate it still exists
await GoogleSheets.getSpreadsheet({ spreadsheetId: storedId });
return storedId;
} catch (error) {
// Spreadsheet no longer accessible, create new
localStorage.removeItem('my_spreadsheet_id');
}
}
// Create new spreadsheet
const result = await GoogleSheets.createSpreadsheet({
title: 'My App Data'
});
localStorage.setItem('my_spreadsheet_id', result.spreadsheetId);
return result.spreadsheetId;
}Update Metadata Row
async function updateMetadata(spreadsheetId: string, key: string, value: string) {
// Read existing metadata
const data = await GoogleSheets.readRange({
spreadsheetId,
range: 'Metadata!A:C'
});
// Find row with matching key
const rowIndex = data.values.findIndex(row => row[0] === key);
const timestamp = new Date().toISOString();
if (rowIndex >= 0) {
// Update existing row
await GoogleSheets.updateRange({
spreadsheetId,
range: `Metadata!A${rowIndex + 1}:C${rowIndex + 1}`,
values: [[key, value, timestamp]]
});
} else {
// Append new row
await GoogleSheets.appendRows({
spreadsheetId,
range: 'Metadata!A:C',
values: [[key, value, timestamp]]
});
}
}Sync Local Data to Sheets
async function syncToSheets(spreadsheetId: string, transactions: any[]) {
// Clear existing data (keep headers)
await GoogleSheets.clearRange({
spreadsheetId,
range: 'Transactions!A2:Z'
});
// Convert objects to 2D array
const values = transactions.map(t => [
t.date,
t.description,
t.amount,
t.category,
t.notes
]);
// Append all rows
await GoogleSheets.appendRows({
spreadsheetId,
range: 'Transactions!A:E',
values
});
console.log(`Synced ${transactions.length} transactions`);
}Platform-Specific Notes
Web (PWA)
- Uses
fetch()API - Token retrieved from
@zeattacker/capacitor-google-authorlocalStorage - Works offline if service worker caches API responses
iOS
- Uses
URLSessionfor HTTP requests - Token retrieved from GoogleAuth plugin
- All network operations run on background thread
- Responses parsed on main thread
Android
- Uses
OkHttpfor HTTP requests - Token retrieved from GoogleAuth plugin
- Network operations run on
ExecutorService - Automatic JSON parsing with Gson
Error Handling
try {
const data = await GoogleSheets.readRange({
spreadsheetId: 'abc123',
range: 'Sheet1!A:D'
});
} catch (error) {
if (error.message.includes('401')) {
// Token expired - refresh auth
await GoogleAuth.refresh();
} else if (error.message.includes('403')) {
// Insufficient permissions - wrong scope
console.error('Missing spreadsheets scope');
} else if (error.message.includes('404')) {
// Spreadsheet not found
console.error('Spreadsheet does not exist');
} else {
console.error('Unknown error:', error);
}
}Common error codes:
401- Unauthorized (token expired or invalid)403- Forbidden (insufficient permissions/wrong scope)404- Not found (spreadsheet or sheet doesn't exist)429- Rate limit exceeded (too many requests)
Troubleshooting
"Not authenticated" Error
Make sure you've signed in with GoogleAuth first:
await GoogleAuth.signIn();"Insufficient permissions" Error
Add the Sheets scope to your GoogleAuth initialization:
await GoogleAuth.initialize({
scopes: ['https://www.googleapis.com/auth/spreadsheets']
});iOS Build Errors
Run pod install:
cd ios/App
pod installAndroid Build Errors
Sync Gradle:
cd android
./gradlew clean buildTypeScript Types
Full TypeScript support with detailed interfaces:
import type {
GoogleSheetsPlugin,
SpreadsheetResult,
ValuesResult,
UpdateResult,
BatchUpdateResult,
ValidationResult,
CellValue
} from '@zeattacker/capacitor-google-sheets';Migration from Direct API Calls
If you're currently using the Google Sheets REST API directly:
Before:
const token = localStorage.getItem('google_access_token');
const response = await fetch(
`https://sheets.googleapis.com/v4/spreadsheets/${id}/values/${range}`,
{
headers: { Authorization: `Bearer ${token}` }
}
);
const data = await response.json();After:
const data = await GoogleSheets.readRange({
spreadsheetId: id,
range: range
});License
MIT
Author
ZeAttacker
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Related Plugins
- @zeattacker/capacitor-google-auth - Google authentication (required)
Changelog
See CHANGELOG.md for release history.