9.1 The Custom Code Node
Built-in columns cover common operations like enrichment APIs, AI models, webhooks, and email. But what if you need something completely unique? That's where Custom Code comes in—it gives you full programming power to build exactly what you need.
What Is the Custom Code Column?
The Concept
A Custom Code column lets you write Groovy code that runs automatically for each row in your taible.
Think of it as:
- A blank canvas for custom logic
- Full access to all data in the row
- Ability to perform complex calculations
- Custom validation and transformations
- Integration with your unique business rules
In simple terms: If you can code it, you can automate it.
Custom Code
Write Groovy code for custom logic
Why Custom Code?
Built-in columns are great for common operations:
- ✅ Data enrichment (Clearbit, Apollo)
- ✅ AI completions (OpenAI, Claude)
- ✅ Send emails
- ✅ Update CRM
But what if you need:
- Custom scoring algorithm with your proprietary formula
- Integration with your internal API
- Complex multi-step data transformation
- Unique business validation rules
- Legacy system connection
Custom Code fills these gaps perfectly.
When to Use Custom Code
Use Case 1: Unique Business Logic
Scenario: Your company has a proprietary lead scoring algorithm.
The Problem: Built-in nodes don't know your specific formula.
The Solution: Write custom code implementing your exact algorithm.
Example: Custom Lead Scoring
Why use Custom Code? Built-in nodes don't have your proprietary scoring formula. Custom Code lets you implement your exact business rules.
Result: Every lead gets automatically scored using your exact business rules.
Use Case 2: Complex Transformations
Scenario: You need to parse, validate, clean, and format address data.
The Problem: Built-in nodes would require 5-10 separate columns.
The Solution: One custom code column does it all.
Example:
// Parse address components
def parts = rawAddress.split(',')
def street = parts[0]?.trim()
def city = parts[1]?.trim()
def stateZip = parts[2]?.trim()
// Extract state and ZIP
def matcher = (stateZip =~ /([A-Z]{2})\s+(\d{5})/)
def state = matcher ? matcher[0][1] : null
def zip = matcher ? matcher[0][2] : null
// Validate completeness
if (!street || !city || !state || !zip) {
return [valid: false, reason: 'Incomplete address']
}
// Return standardized format
return [
street: street.toUpperCase(),
city: city.toUpperCase(),
state: state,
zip: zip,
valid: true
]Result: Complex transformation in a single column instead of many.
Use Case 3: Custom Validation
Scenario: You have complex B2B validation rules.
Example: Email domain must match company, revenue in range, industry allowed.
def errors = []
// Check email domain matches company
def emailDomain = email.split('@')[1]
if (!companyName.toLowerCase().contains(emailDomain.split('\\.')[0])) {
errors.add('Email domain mismatch')
}
// Check revenue range
if (revenue < 1000000 || revenue > 1000000000) {
errors.add('Revenue outside target range')
}
// Check blocked industries
def blockedIndustries = ['Gambling', 'Tobacco']
if (industry in blockedIndustries) {
errors.add("Industry not allowed: ${industry}")
}
return [
valid: errors.isEmpty(),
errors: errors,
status: errors.isEmpty() ? 'APPROVED' : 'REJECTED'
]Result: Comprehensive validation with your business logic.
Use Case 4: Custom Algorithms
Scenario: You need fuzzy matching to detect duplicate company names.
Example: Levenshtein distance algorithm for similarity scoring.
// Calculate similarity between two strings
def calculateSimilarity(String s1, String s2) {
// Levenshtein distance implementation
def costs = new int[s2.length() + 1]
for (int j = 0; j <= s2.length(); j++) costs[j] = j
for (int i = 1; i <= s1.length(); i++) {
costs[0] = i
int nw = i - 1
for (int j = 1; j <= s2.length(); j++) {
int cj = Math.min(
Math.min(costs[j] + 1, costs[j - 1] + 1),
s1.charAt(i - 1) == s2.charAt(j - 1) ? nw : nw + 1
)
nw = costs[j]
costs[j] = cj
}
}
return costs[s2.length()]
}
// Find similar company names
def targetName = inputCompanyName
def existingNames = allCompanies // From another column
def matches = existingNames.collect { name ->
[
name: name,
distance: calculateSimilarity(targetName.toLowerCase(), name.toLowerCase())
]
}.findAll { it.distance <= 3 }
return [
matches: matches,
isDuplicate: !matches.isEmpty()
]Result: Custom matching algorithm tailored to your needs.
Programming Language: Groovy
What Is Groovy?
Groovy is a programming language that runs on the Java Virtual Machine (JVM).
Key characteristics:
- Similar syntax to JavaScript/Python - easy to learn
- Dynamic typing - less verbose than Java
- Powerful features - lists, maps, string interpolation
- Access to Java libraries - extensive ecosystem
Why Groovy?
Advantages for Taibles:
- Easy to learn: Python-like simplicity
- Powerful: Full Java ecosystem access
- Safe: Runs in controlled environment
- Flexible: Dynamic typing with type inference
- String interpolation: Easy data manipulation
Groovy Basics for Non-Programmers
If you're not a developer, Groovy is surprisingly approachable:
Groovy Basics for Beginners
Variables (storing data)
Conditionals (if/else)
Inserting Variables into Text
Math Operations
Good news: Groovy syntax is similar to JavaScript, Python, and Java. If you know any programming language, you'll pick it up quickly!
Learning Resources
Want to learn Groovy?
- Official Groovy docs: https://groovy-lang.org/documentation.html
- Online tutorials: Groovy Koans, interactive exercises
- Stack Overflow: Active Groovy community
Or hire a developer: Many freelancers and agencies know Groovy and can write custom code for you!
What You Can Do with Custom Code
Capability 1: Access All Row Data
You can access any column in the current row:
def customerEmail = [Email Column]
def companyName = [Company Name]
def enrichmentData = [Enrichment Result]When you type in the code editor, press CTRL+SPACE to see all available columns. They appear as colored badges in your code.
Capability 2: Complex Calculations
Mathematical operations:
def orderTotal = [Quantity] * [Unit Price]
def discount = orderTotal * 0.1
def finalPrice = orderTotal - discount
return finalPriceStatistical calculations:
def scores = [All Scores] // Array from another column
def average = scores.sum() / scores.size()
def maximum = scores.max()
def minimum = scores.min()
return [average: average, max: maximum, min: minimum]Capability 3: String Manipulation
Text processing:
def fullName = [Full Name]
// Split into first and last name
def parts = fullName.split(' ')
def firstName = parts[0]
def lastName = parts.size() > 1 ? parts[1..-1].join(' ') : ''
// Format different ways
return [
first: firstName,
last: lastName,
formal: "Mr./Ms. ${lastName}",
informal: firstName
]Capability 4: Data Structure Manipulation
Working with lists and objects:
def contacts = [Contact List] // Array from another column
// Filter active contacts
def activeContacts = contacts.findAll { it.status == 'active' }
// Extract just emails
def emails = activeContacts.collect { it.email }
// Group by industry
def byIndustry = contacts.groupBy { it.industry }
return [
total: contacts.size(),
active: activeContacts.size(),
emails: emails,
byIndustry: byIndustry
]Capability 5: Conditional Logic
Complex decision trees:
def score = [Lead Score]
def revenue = [Company Revenue]
def industry = [Industry]
def tier = 'C'
if (score > 80 && revenue > 10000000) {
tier = 'A'
} else if (score > 60 && revenue > 1000000) {
tier = 'B'
} else if (industry in ['Technology', 'Finance']) {
tier = 'B' // Upgrade strategic industries
}
def actions = []
if (tier == 'A') {
actions = ['Assign to senior sales', 'Schedule executive call']
} else if (tier == 'B') {
actions = ['Assign to mid-level sales', 'Send personalized email']
} else {
actions = ['Add to nurture campaign']
}
return [tier: tier, actions: actions]Capability 6: Return Any Type of Data
Your code can return:
- Simple values: strings, numbers, booleans
- Objects: maps with multiple properties
- Arrays: lists of items
- Nested data: complex structures
Example:
// Return an object with multiple fields
return [
status: 'valid',
score: 85,
tier: 'A',
actions: ['Call', 'Email'],
metadata: [
processedAt: new Date(),
version: '1.0'
]
]How Results Display
When your code runs, the results appear in each cell:
How Results Display
Click on any result to see the full data in a sidebar with a formatted JSON view.
Click any result to see the full data in a detailed sidebar view with formatted JSON.
Configuring a Custom Code Column
When you add a Custom Code column, you configure two things:
Configure Custom Code Column
1. Output Type
Tell the system what type of data your code returns:
String- TextIntegerorDouble- NumbersBoolean- True/falseList<String>- List of text itemsMap<String, Object>- Object with propertiesany- Any type (default)
2. Code to Execute
Write your Groovy code in the editor:
- Line numbers on the left
- Syntax highlighting for easier reading
- CTRL+SPACE shows available columns
- Colored badges show where you're using data from other columns
- Current line highlighting shows where your cursor is
💡 Pro Tip
Important Limitations
Security Considerations
Current status: Custom code runs with full access to the system.
What this means:
- Only use Custom Code for your own automations
- Don't allow untrusted users to write code
- Future versions will add sandboxing for safety
Best practice: Treat Custom Code like admin access—use it carefully.
No Direct HTTP Calls
Custom Code doesn't include HTTP libraries for API calls.
For API integrations:
- Option 1: Use built-in API nodes where available
- Option 2: Request a custom node for your specific API
- Option 3: Use RPC node for HTTP calls (if available)
Performance Considerations
Your code executes for every row:
- Complex code = slower processing
- Heavy calculations affect performance
- Consider rate limits if needed
Optimization tip: Keep code simple and efficient. If you're processing thousands of rows, every millisecond counts!
Debugging Can Be Tricky
Challenges:
- Errors show in cell results
- No step-by-step debugger
- Stack traces can be technical
Best practices:
- Start simple, test incrementally
- Use
returnstatements to check intermediate values - Test with one row before running on many
- Check for null values: use
?.safe navigation
Example of safe coding:
// ❌ Might crash if data is missing
def domain = email.split('@')[1]
// ✅ Safely handles missing data
def domain = email?.split('@')?.getAt(1)When NOT to Use Custom Code
Don't Use When Built-In Nodes Exist
If there's already a node for what you need, use it:
- More reliable (tested by many users)
- Better error handling
- Maintained and updated
- Often more performant
Example:
- ❌ Don't write HTTP client code for Clearbit
- ✅ Use the Clearbit enrichment node
Don't Use for Simple Operations
For simple data manipulation, use dependencies and templates.
Bad (unnecessarily complex):
// Custom Code column
def firstName = [First Name]
def lastName = [Last Name]
return "${firstName} ${lastName}"Good (use column dependencies): Just reference the data directly: The system automatically combines [First Name] and [Last Name].
Rule: If you can do it with column dependencies, don't use Custom Code.
Don't Duplicate Logic
If you're writing the same code in multiple columns:
- Create a reusable column template
- Or request a custom node
- Don't copy-paste code everywhere
Why? Duplicated code = maintenance nightmare when you need to change it later.
Getting Help with Custom Code
If You're Not Technical
You don't need to be a programmer! Here's how to work with developers:
1. Describe your business logic clearly:
- What data do you start with?
- What do you want to calculate or validate?
- What should the output look like?
- What are the edge cases?
2. Provide examples:
- Sample input data
- Expected output for each example
- Any special rules or conditions
3. Developer writes the code
4. You test it:
- Create test rows with different scenarios
- Verify the results match expectations
- Report any issues
Where to find developers:
- Upwork, Toptal (freelance platforms)
- Local development agencies
- Groovy/Java developer communities
Resources
Learn Groovy:
- Official docs: https://groovy-lang.org/documentation.html
- Interactive tutorials online
- Stack Overflow for questions
Get help:
- Hire a developer for custom logic
- Check existing examples in documentation
- Ask in Taibles community
Real-World Examples
Example 1: Email Classification
def email = [Email]
if (email.contains('@gmail.com') || email.contains('@yahoo.com')) {
return 'Personal'
} else if (email.contains('@company.com')) {
return 'Internal'
} else {
return 'Business'
}Example 2: Price Calculation with Tiers
def quantity = [Quantity]
def basePrice = [Base Price]
def price = basePrice
if (quantity >= 100) {
price = basePrice * 0.8 // 20% discount
} else if (quantity >= 50) {
price = basePrice * 0.9 // 10% discount
}
return price * quantityExample 3: Data Quality Check
def issues = []
if ([Email] == null || ![Email].contains('@')) {
issues.add('Invalid email')
}
if ([Company Name] == null || [Company Name].length() < 2) {
issues.add('Invalid company name')
}
if ([Phone] != null && ![Phone].matches('\\d{10,}')) {
issues.add('Invalid phone format')
}
return [
valid: issues.isEmpty(),
issues: issues
]Summary: The Custom Code Column
You now understand Custom Code columns:
✅ What it is: Groovy code execution for custom logic
✅ When to use it:
- Unique business logic
- Complex transformations
- Custom validation
- Proprietary algorithms
- Data quality checks
✅ What you can do:
- Access all row data
- Complex calculations
- String manipulation
- Data structure operations
- Conditional logic
- Return any data type
✅ How it works:
- Configure output type
- Write code in editor with syntax highlighting
- Press CTRL+SPACE for column autocomplete
- Results display in colored badges
- Click for detailed view
✅ Limitations:
- Security (use carefully)
- No direct HTTP calls
- Performance considerations
- Debugging challenges
✅ When NOT to use:
- Built-in node exists
- Simple operations
- Duplicating logic
✅ Getting help:
- Learn Groovy basics
- Hire a developer
- Community resources
Next Steps
Now that you understand the concept, Section 9.2 will show you:
- Step-by-step: Adding a Custom Code column
- Configuring the code editor
- Testing your code
- Viewing results
- Troubleshooting common issues
Let's build with custom code! 🚀