How to Use PropertiesService to Store Secrets in Apps Script

Hardcoding API keys and credentials directly into your script is a security risk — especially if you share scripts with others or use version control. PropertiesService is Apps Script's built-in solution for storing sensitive configuration values securely.

What is PropertiesService?

PropertiesService provides three stores for key-value pairs:

StoreScopeUse case
ScriptPropertiesAll users, all runs of this scriptAPI keys, shared config
UserPropertiesCurrent user only, across all scriptsUser-specific preferences
DocumentPropertiesCurrent document onlyDocument-specific settings

For API keys and secrets, ScriptProperties is usually the right choice.

Storing a secret

Run this function once to save your API key — then delete the code (you don't want it to accidentally re-run):

function storeApiKey() { const scriptProperties = PropertiesService.getScriptProperties(); scriptProperties.setProperty('OPENWEATHER_API_KEY', 'your_actual_api_key_here'); scriptProperties.setProperty('SLACK_WEBHOOK_URL', 'https://hooks.slack.com/...'); Logger.log('Secrets stored.'); }

Alternatively, set properties directly in the Apps Script editor:

  1. Go to Project Settings (gear icon in left sidebar).
  2. Scroll to Script Properties.
  3. Click Add script property and enter your key-value pairs.

Reading a stored secret

function fetchWeatherData() { const apiKey = PropertiesService.getScriptProperties().getProperty('OPENWEATHER_API_KEY'); if (!apiKey) { throw new Error('OPENWEATHER_API_KEY not set. Add it in Project Settings > Script Properties.'); } const city = 'London'; const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`; const response = UrlFetchApp.fetch(url); const data = JSON.parse(response.getContentText()); Logger.log(`Temperature in ${city}: ${data.main.temp}°C`); }

Store and retrieve multiple properties at once

function storeMultipleProperties() { PropertiesService.getScriptProperties().setProperties({ 'DB_HOST': 'db.example.com', 'DB_USER': 'admin', 'DB_PASS': 'super_secret_password' }); } function getAllProperties() { const props = PropertiesService.getScriptProperties().getProperties(); // props is a plain object: { 'DB_HOST': '...', 'DB_USER': '...', ... } Logger.log(JSON.stringify(props)); }

UserProperties for per-user preferences

function saveUserPreference() { const userProps = PropertiesService.getUserProperties(); userProps.setProperty('REPORT_EMAIL', Session.getActiveUser().getEmail()); userProps.setProperty('TIMEZONE', 'America/New_York'); } function getUserPreference() { const userProps = PropertiesService.getUserProperties(); const tz = userProps.getProperty('TIMEZONE') || 'UTC'; Logger.log('User timezone: ' + tz); }

Delete a property

function cleanupProperties() { const scriptProps = PropertiesService.getScriptProperties(); // Delete one scriptProps.deleteProperty('OLD_API_KEY'); // Delete all (use with caution!) // scriptProps.deleteAllProperties(); }

Best practices

  • Never hardcode secrets — even temporarily. Use the Project Settings UI to set them instead of writing setProperty in code.
  • Validate on startup — check that required properties exist at the top of your main function and throw a clear error if they're missing.
  • Don't log secrets — avoid Logger.log(apiKey). Log only that the key was found, not its value.
  • Property values are strings — if you need to store a number or boolean, use JSON.stringify() when storing and JSON.parse() when reading.
  • Size limit — each property value can be up to 9 KB and you can store up to 500 KB total per store.