Skip to content

9.3 Custom Code Examples ​

You know how to add Custom Code columns and write basic scripts. Now let's explore real-world examples you can adapt for your automations. Each example shows the business problem, the solution, and how to implement it.


Example 1: Lead Scoring Algorithm ​

The Business Problem ​

Challenge: You need to score leads based on multiple factors—company size, industry, engagement, contact role, and more. Each factor has different weight.

Manual approach: Would require spreadsheet with complex formulas, or manual review

Custom code solution: Automated scoring that adapts to your criteria


The Setup ​

Create these columns first:

Column NameTypeDescription
EmailTextContact email
Contact RoleTextJob title
Email OpensNumberEmail open count
Link ClicksNumberLink click count
Company Data(From enrichment)Company information
Lead ScoreCustom CodeThis is what we're building

The Code ​

When adding the Lead Score column:

  1. Click + Add Column

  2. Choose Custom Code column type

  3. Enter configuration:

    • Column name: lead_score
    • Display label: "Lead Score"
    • Output type: Map<String, Object>
  4. Write your code:

groovy
// Custom lead scoring based on multiple factors
let score = 0

// Factor 1: Company size score
let companySize = [Company Size] || 0
if (companySize > 1000) {
  score += 30
} else if (companySize > 100) {
  score += 20
} else if (companySize > 10) {
  score += 10
}

// Factor 2: Industry score
let industry = [Industry]
let targetIndustries = ['Technology', 'Finance', 'Healthcare']
if (targetIndustries.includes(industry)) {
  score += 25
}

// Factor 3: Engagement score
let emailOpens = [Email Opens] || 0
let linkClicks = [Link Clicks] || 0
score += emailOpens * 2
score += linkClicks * 5

// Factor 4: Role score
let role = [Contact Role]
if (role && (role.includes('Director') || role.includes('VP'))) {
  score += 20
}
if (role && (role.includes('C-level') || role.includes('CEO'))) {
  score += 30
}

// Factor 5: Email domain score (educational institutions)
let email = [Email]
if (email && email.endsWith('.edu')) {
  score += 15
}

// Return structured result
return {
  total_score: score,
  grade: score > 70 ? 'A' : score > 50 ? 'B' : score > 30 ? 'C' : 'D',
  qualified: score > 50
}

How It Works ​

Input: Multiple data points about the lead

Processing:

  1. Company size (0-30 points): Larger companies score higher
  2. Industry (0-25 points): Target industries get bonus
  3. Engagement (0-∞ points): More interaction = higher score
  4. Role (0-30 points): Decision-makers score higher
  5. Email domain (0-15 points): Educational institutions get bonus

Output: Object with three fields:

  • total_score: Numeric score (0-100+)
  • grade: Letter grade (A/B/C/D)
  • qualified: Boolean (true if score > 50)

Lead Scoring Results

Custom code calculates scores based on multiple factors

EmailRoleCompanyIndustryScoreGrade
john@bigtech.comVP Engineering1500 employeesTechnology85A
sarah@startup.ioDeveloper25 employeesTechnology45C
mike@hospital.eduCTO800 employeesHealthcare75B
jane@retail.comManager50 employeesRetail25D

Scoring Factors:

  • ✅ Company Size: 0-30 points
  • ✅ Industry Match: 0-25 points
  • ✅ Decision Maker Role: 0-30 points
  • ✅ Email Domain: 0-15 points

Using the Results ​

In another column (e.g., filter qualified leads):

Create a new column and reference the Lead Score:

groovy
let scoring = [Lead Score]
let isQualified = scoring.qualified || false

if (isQualified) {
  return "ROUTE TO SALES"
} else {
  return "ROUTE TO NURTURE"
}

Or as a condition on other columns:

  • Open the column's Run Configuration
  • Add a condition: "Only run if lead is qualified"
  • The system checks Lead Score.qualified == true

Customizing for Your Business ​

Change target industries:

Find this line in the code:

groovy
let targetIndustries = ['Technology', 'Finance', 'Healthcare']

Replace with your industries:

groovy
let targetIndustries = ['Manufacturing', 'Retail', 'Logistics']

Adjust scoring weights:

Give more weight to engagement:

groovy
score += emailOpens * 5  // Changed from 2
score += linkClicks * 10 // Changed from 5

Add new factors:

groovy
// Factor 6: Geographic score
let country = [Country]
if (country === 'United States') {
  score += 20
}

Example 2: Data Cleaning and Standardization ​

The Business Problem ​

Challenge: Phone numbers come in various formats—some with country codes, some with dashes, some with parentheses. You need consistent format for CRM integration.

Examples of messy data:

  • (555) 123-4567
  • 555-123-4567
  • 5551234567
  • +1 555 123 4567
  • 1-555-123-4567

Need: All formatted as +1 (555) 123-4567


The Setup ​

Create these columns:

Column NameTypeDescription
Raw PhoneTextPhone number as entered
Standardized PhoneCustom CodeCleaned format

The Code ​

When adding Standardized Phone column:

  1. Add Custom Code column

  2. Configuration:

    • Column name: standardized_phone
    • Display label: "Phone Number"
    • Output type: String
  3. Write code:

groovy
// Standardize phone numbers
let phone = [Raw Phone]

// Return null if no phone
if (!phone) return null

// Remove all non-numeric characters
phone = phone.replace(/[^\d]/g, '')

// Format based on length
if (phone.length === 10) {
  // US format (no country code)
  return `+1 (${phone.slice(0,3)}) ${phone.slice(3,6)}-${phone.slice(6)}`
} else if (phone.length === 11 && phone[0] === '1') {
  // US with leading 1
  return `+${phone[0]} (${phone.slice(1,4)}) ${phone.slice(4,7)}-${phone.slice(7)}`
} else if (phone.length > 11) {
  // International (keep as is with + prefix)
  return `+${phone}`
} else {
  // Invalid length - return cleaned but not formatted
  return phone
}

How It Works ​

Step 1: Remove all non-numeric characters

  • (555) 123-4567 → 5551234567
  • +1-555-123-4567 → 15551234567

Step 2: Identify format based on length

  • 10 digits: US number without country code
  • 11 digits starting with 1: US number with country code
  • Other: International format

Step 3: Apply formatting

  • US: +1 (555) 123-4567
  • International: + followed by digits

Phone Number Standardization

Custom code converts messy formats to consistent standard

Before
(555) 123-4567
After
+1 (555) 123-4567
Before
555-123-4567
After
+1 (555) 123-4567
Before
5551234567
After
+1 (555) 123-4567
Before
+1 555 123 4567
After
+1 (555) 123-4567
Before
1-555-123-4567
After
+1 (555) 123-4567

What the code does:

  1. Removes all non-numeric characters
  2. Detects format based on digit count
  3. Applies US phone number formatting
  4. Adds country code (+1)

Testing ​

Test data to add:

Raw PhoneExpected Result
(555) 123-4567+1 (555) 123-4567
5551234567+1 (555) 123-4567
+1 555-123-4567+1 (555) 123-4567
442012345678+442012345678

Add these rows and verify all formats convert correctly!


Variations ​

For other countries (e.g., UK):

groovy
let phone = [Raw Phone]
if (!phone) return null

phone = phone.replace(/[^\d]/g, '')

if (phone.length === 10 && !phone.startsWith('44')) {
  // UK number without country code
  return `+44 ${phone.slice(0,4)} ${phone.slice(4,7)} ${phone.slice(7)}`
} else if (phone.length === 12 && phone.startsWith('44')) {
  // UK with country code
  return `+${phone.slice(0,2)} ${phone.slice(2,6)} ${phone.slice(6,9)} ${phone.slice(9)}`
} else {
  return `+${phone}`
}

For email standardization:

groovy
let email = [Raw Email]
if (!email) return null

// Convert to lowercase
email = email.toLowerCase().trim()

// Validate format
if (!email.includes('@') || !email.includes('.')) {
  return null // Invalid email
}

return email

Example 3: Smart Caching with Conditional Processing ​

The Business Problem ​

Challenge: API enrichment is expensive ($1 per call). You don't want to call API every time—only when data is stale or missing.

Solution: Cache results, only refresh if older than 7 days

Savings: 90% reduction in API calls (refresh weekly vs. daily)


The Setup ​

Create these columns:

Column NameTypeDescription
EmailTextEmail to enrich
Cached Enrichment(Previous enrichment)Previous result
Smart EnrichmentCustom CodeSmart caching logic

The Code ​

When adding Smart Enrichment column:

  1. Add Custom Code column

  2. Configuration:

    • Column name: smart_enrichment
    • Display label: "Enrichment (Cached)"
    • Output type: Map<String, Object>
  3. Write code:

groovy
let email = [Email]
let existingData = [Cached Enrichment]

// Check if cached data exists and is recent
if (existingData && existingData.cached_at) {
  try {
    // Calculate cache age in days
    let cachedDate = new Date(existingData.cached_at)
    let currentDate = new Date()
    let cacheAge = (currentDate - cachedDate) / (1000 * 60 * 60 * 24)

    // If cache is less than 7 days old, return it
    if (cacheAge < 7) {
      return {
        from_cache: true,
        cache_age_days: Math.round(cacheAge * 10) / 10,
        data: existingData
      }
    }
  } catch (e) {
    // If date parsing fails, proceed to fetch fresh data
  }
}

// No cache or cache is stale
// In real implementation, this would trigger your enrichment column
return {
  from_cache: false,
  needs_refresh: true,
  email: email,
  message: 'Cache miss - fresh data needed'
}

How It Works ​

Decision tree:

Is there cached data?
├─ NO → Fetch fresh (call API)
└─ YES → Is cache < 7 days old?
    ├─ YES → Return cached (save $1)
    └─ NO → Fetch fresh (call API)

Cache hit (within 7 days):

  • Returns existing data
  • Sets from_cache: true
  • Shows cache age

Cache miss (> 7 days or no cache):

  • Returns marker
  • Would trigger API call (in real implementation)
  • Updates cache

Smart Caching in Action

Only refreshes data older than 7 days

EmailLast EnrichedStatusCost
john@example.com2 days agoUsing Cache$0
sarah@example.com5 days agoUsing Cache$0
mike@example.com8 days agoRefreshing$1
jane@example.comNeverNew Call$1

❌ Without Caching

$30,000

30,000 API calls per month

✅ With Caching

$4,300

4,300 API calls per month (86% savings!)


Cost Savings ​

Without caching:

  • 1,000 leads
  • Run daily for 30 days
  • 30,000 API calls
  • Cost: $30,000

With caching (7-day refresh):

  • Initial: 1,000 API calls
  • Weekly refresh: ~143 calls per day (1000 ÷ 7)
  • Monthly: ~4,300 calls
  • Cost: $4,300
  • Savings: $25,700 (86%)

Example 4: Data Aggregation and Reporting ​

The Business Problem ​

Challenge: Calculate summary statistics from multiple columns—total orders, average order value, conversion rate.

Manual approach: Export to Excel, create pivot table

Custom code solution: Real-time calculation in taible


The Setup ​

Create these columns:

Column NameTypeDescription
Orders(Collection of orders)Array of orders
Leads(Collection of leads)Array of leads
Summary StatsCustom CodeAggregated statistics

The Code ​

groovy
// Get data
let orders = [Orders] || []
let leads = [Leads] || []

// Calculate order statistics
let totalOrders = orders.length
let totalRevenue = orders.reduce((sum, order) => sum + (order.amount || 0), 0)
let avgOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0

// Calculate lead statistics
let totalLeads = leads.length
let qualifiedLeads = leads.filter(lead => lead.qualified === true).length
let conversionRate = totalLeads > 0 ? (totalOrders / totalLeads) * 100 : 0

// Find top order
let topOrder = orders.reduce((max, order) =>
  (order.amount || 0) > (max.amount || 0) ? order : max
, {})
let topOrderAmount = topOrder.amount || 0

// Calculate time-based metrics
let now = new Date()
let ordersThisMonth = orders.filter(order => {
  if (!order.date) return false
  let orderDate = new Date(order.date)
  return orderDate.getMonth() === now.getMonth() &&
         orderDate.getFullYear() === now.getFullYear()
}).length

// Return comprehensive summary
return {
  // Order metrics
  total_orders: totalOrders,
  total_revenue: Math.round(totalRevenue * 100) / 100,
  avg_order_value: Math.round(avgOrderValue * 100) / 100,
  top_order_amount: topOrderAmount,
  orders_this_month: ordersThisMonth,

  // Lead metrics
  total_leads: totalLeads,
  qualified_leads: qualifiedLeads,
  qualification_rate: Math.round((qualifiedLeads / totalLeads) * 1000) / 10,

  // Performance metrics
  conversion_rate: Math.round(conversionRate * 100) / 100,

  // Summary
  status: totalOrders > 0 ? 'ACTIVE' : 'NO_ORDERS',
  performance: conversionRate > 5 ? 'GOOD' : conversionRate > 2 ? 'AVERAGE' : 'NEEDS_IMPROVEMENT'
}

Output Example ​

The cell will display a structured object:

Real-Time Summary Statistics

Custom code calculates metrics from multiple columns

Total Orders
47
Total Revenue
$28,450.75
Avg Order Value
$605.33
Orders This Month
12
Total Leads
850
Qualified Leads
340
Conversion Rate
5.53%
ACTIVE
Performance: GOOD

Using in Other Columns ​

Access individual metrics in another column:

groovy
let stats = [Summary Stats]
let revenue = stats.total_revenue || 0
let conversionRate = stats.conversion_rate || 0

return `Revenue: $${revenue}, Conversion: ${conversionRate}%`

Or display formatted in a dashboard


Common Code Patterns ​

Pattern 1: Safe Data Access ​

Always use fallback values to prevent errors:

groovy
let value = [Column Name] || 'default'
let number = [Number Column] || 0
let array = [List Column] || []

Pattern 2: Conditional Return ​

Exit early if required data is missing:

groovy
if (!requiredField) return null
// ... rest of code only runs if field exists

Pattern 3: Error Handling ​

Wrap risky operations:

groovy
try {
  let result = riskyOperation()
  return result
} catch (e) {
  return { error: true, message: e.message }
}

Pattern 4: Calculate and Format ​

Round numbers for display:

groovy
let total = items.reduce((sum, item) => sum + item.amount, 0)
return Math.round(total * 100) / 100 // 2 decimal places

Pattern 5: Filter and Transform Collections ​

Process arrays:

groovy
let filtered = items.filter(item => item.status === 'active')
let names = filtered.map(item => item.name)
return names

Viewing Your Code Results ​

In the Cell ​

When a Custom Code column executes successfully, you'll see:

Custom Code Column Configuration

Write your own logic to process data

Access column data, write custom logic, and return results

  • A green checkmark badge with the result
  • Click the cell to expand and see the full object structure
  • If it returns an object, you'll see a structured view

In the Sidebar ​

Click any Custom Code cell to open the sidebar and see:

  • Full JSON structure of the result
  • All nested properties and values
  • Copy values for use elsewhere

Summary: Custom Code Examples ​

You now have real-world examples:

✅ Lead Scoring: Multi-factor scoring algorithm with grades

✅ Data Cleaning: Phone number standardization with format detection

✅ Smart Caching: Conditional processing to save API costs

✅ Data Aggregation: Calculate summary statistics from collections

Next steps:

  1. Choose an example that fits your use case
  2. Adapt the code to your column names
  3. Test with sample data
  4. Customize logic for your business rules

Next Steps ​

You've completed Chapter 9: Custom Code Columns! You can now:

✅ Understand when to use custom code ✅ Add Custom Code columns via UI ✅ Write scripts for automation ✅ Implement real-world examples ✅ Access data, handle errors, and optimize performance

Next chapter will explore additional advanced features and best practices for building complex automations.

Let's continue building! 🚀

Built with VitePress