Skip to main content

Overview

ctx.thisRow provides convenient methods to read and write data on the currently executing row. This is the most common way to interact with your data within column formulas.
ctx.thisRow is not available in webhook columns, as there is no “current row” context during webhook execution.

Methods

get()

Get a value from the current row by column name.
ctx.thisRow.get(columnName: string): any
Parameters:
  • columnName - The name of the column to read from
Returns: The value stored in that column for the current row Example:
const email = ctx.thisRow.get("email");
const companyName = ctx.thisRow.get("company");

Foreign Key Navigation

For foreign key columns, use the referenced sheet name instead of the column name, and use dot notation to access fields on the related record:
// If "company_id" is a foreign key to the "Companies" sheet
const companyName = ctx.thisRow.get("Companies.name");
const companyWebsite = ctx.thisRow.get("Companies.website");

// You can chain through multiple relationships
const ownerEmail = ctx.thisRow.get("Companies.Owner.email");

set()

Set one or more values on the current row.
ctx.thisRow.set(values: Record<string, any>): void
Parameters:
  • values - An object mapping column names to new values
Example:
// Set a single value
ctx.thisRow.set({ status: "processed" });

// Set multiple values at once
ctx.thisRow.set({
   status: "enriched",
   lastUpdated: new Date().toISOString(),
   score: 95,
});
Using ctx.thisRow.set() with multiple fields is more efficient than creating separate “helper columns” for each intermediate value.

run()

Manually trigger execution of the current row’s formulas.
ctx.thisRow.run(): void
Example:
// After updating values, re-run formulas
ctx.thisRow.set({ input: "new value" });
ctx.thisRow.run();

getRelatedRows()

Get all rows from a related sheet that have a foreign key pointing to the current row.
ctx.thisRow.getRelatedRows(sheetName: string): Row[]
Parameters:
  • sheetName - The name of the sheet to query for related rows
Returns: Array of Row objects that reference the current row Example:
// Get all jobs posted by this company
const jobs = ctx.thisRow.getRelatedRows("Jobs");

// Calculate metrics
const openJobs = jobs.filter((job) => job.get("status") === "open");
const totalApplicants = jobs.reduce((sum, job) => sum + job.get("applicant_count"), 0);

ctx.thisRow.set({
   open_jobs_count: openJobs.length,
   total_applicants: totalApplicants,
});

Row Object

When you work with rows (from getRelatedRows or other methods), each Row object has the following properties and methods:

Properties

  • row.id - UUID of the row
  • row.index - Numeric index of the row (0-based)
  • row.wasCreated - Boolean indicating if this row was newly created (via addRow)
  • row.wasUpdated - Boolean indicating if this row was updated (via addRow with unique column match)

Methods

  • row.get(columnName) - Get a value from this row
  • row.set(values) - Set values on this row
  • row.run(options?) - Trigger execution of this row’s formulas
    • options.excludeColumns - Array of column names to skip during execution
Example:
const relatedJobs = ctx.thisRow.getRelatedRows("Jobs");

for (const job of relatedJobs) {
   console.log(`Job ${job.index}: ${job.get("title")}`);

   // Update the job
   job.set({ lastChecked: new Date().toISOString() });

   // Re-run formulas, but skip expensive columns
   job.run({ excludeColumns: ["ai_analysis"] });
}

Common Patterns

Conditional Enrichment Based on Lead Status

// Only enrich qualified leads
const status = ctx.thisRow.get("Status");
const companySize = ctx.thisRow.get("Employee Count");

if (status === "Qualified" && companySize >= 50) {
   // Perform deep enrichment for qualified prospects
   const linkedinUrl = ctx.thisRow.get("LinkedIn URL");
   const data = await services.company.linkedin.enrich({
      url: linkedinUrl,
      enrichLevel: "extended",
   });

   ctx.thisRow.set({
      "Status": "Enriched",
      "Industry": data.industry,
      "Active Jobs": data.active_job_postings_count,
      "Growth Signal": data.active_job_postings_count > 10 ? "High Growth" : "Stable",
      "Priority": data.active_job_postings_count > 10 ? "High" : "Medium",
   });
}

Aggregating Contacts at an Account

// Aggregate all contacts associated with this account
const contacts = ctx.thisRow.getRelatedRows("Contacts");

// Calculate account metrics
const decisionMakers = contacts.filter((c) => 
   c.get("Title")?.match(/(CEO|CTO|CFO|VP|Vice President|Director)/i)
);

const hasEmail = contacts.filter((c) => c.get("Email")).length;
const hasPhone = contacts.filter((c) => c.get("Phone")).length;

ctx.thisRow.set({
   "Total Contacts": contacts.length,
   "Decision Makers": decisionMakers.length,
   "Contacts with Email": hasEmail,
   "Contacts with Phone": hasPhone,
   "Account Completeness": Math.round((hasEmail / contacts.length) * 100) + "%",
});

Create Contacts from Company Employees

// Extract decision makers from company and create contact records
const companyName = ctx.thisRow.get("Company Name");
const companyLinkedin = ctx.thisRow.get("Company LinkedIn");
const employees = await services.company.getEmployees({
   linkedinCompanyUrl: companyLinkedin,
});

// Filter for decision makers
const decisionMakers = employees.filter(emp => 
   emp.title?.match(/(CEO|CTO|CFO|VP|Vice President|Director|Head of)/i)
);

// Create contact records for each decision maker
for (const dm of decisionMakers.slice(0, 10)) {
   await ctx.sheet("Contacts").addRow({
      "Name": dm.name,
      "Title": dm.title,
      "Company": companyName,
      "LinkedIn URL": dm.linkedinUrl,
      "Source": "Company Employee List",
   });
}

ctx.thisRow.set({ 
   "Contacts Created": decisionMakers.slice(0, 10).length,
   "Status": "Contacts Extracted",
});