ESG Document Intelligence
Overview
This skill extracts and analyzes Environmental, Social, and Governance (ESG) data from documents and ServiceNow records. It covers:
- Extracting energy consumption, carbon emissions, and waste data from utility invoices and reports
- Mapping extracted metrics to ESG framework requirements (GRI, SASB, TCFD, CDP, CSRD)
- Tracking Scope 1, 2, and 3 greenhouse gas emissions across facilities and time periods
- Analyzing disclosure completeness against regulatory and voluntary reporting frameworks
- Generating ESG performance dashboards with trend analysis and benchmarking
- Identifying data gaps that could impact disclosure accuracy or compliance
When to use:
- During annual ESG/sustainability report preparation
- When processing utility invoices to update environmental metrics
- Before CDP, GRI, or CSRD disclosure submissions
- When leadership needs a snapshot of environmental performance
- During ESG audits requiring metric traceability to source documents
Prerequisites
- Roles:
sn_esg.admin,sn_esg.manager,sn_esg.data_entry, oradmin - Plugins:
com.sn_esg(ESG Management) - Access: Read/write access to sn_esg_metric, sn_esg_disclosure, sn_esg_framework tables
- Knowledge: Understanding of ESG frameworks (GRI Standards, SASB, TCFD), GHG Protocol for emissions accounting, and your organization's materiality assessment
Key ESG Tables
| Table | Purpose | Key Fields |
|---|---|---|
sn_esg_metric |
ESG performance metrics | number, metric_name, category, value, unit, period, location, scope, framework, data_source |
sn_esg_disclosure |
Framework disclosure responses | number, framework, disclosure_id, response, status, evidence, reporting_period, reviewer |
sn_esg_framework |
ESG framework definitions | name, version, category, standard_body, active, disclosure_count |
sn_esg_data_point |
Raw data points from sources | metric, value, date, source_document, location, verified, notes |
cmn_location |
Facility/location records | name, city, state, country, building, latitude, longitude |
Procedure
Step 1: Query Existing ESG Metrics
Retrieve current ESG metrics to understand the baseline.
Using MCP (Claude Code/Desktop):
Tool: SN-Query-Table
Parameters:
table_name: sn_esg_metric
query: active=true^ORDERBYcategory
fields: sys_id,number,metric_name,category,value,unit,period,location,scope,framework,data_source,last_updated
limit: 100
Using REST API:
GET /api/now/table/sn_esg_metric?sysparm_query=active=true^ORDERBYcategory&sysparm_fields=sys_id,number,metric_name,category,value,unit,period,location,scope,framework,data_source,last_updated&sysparm_limit=100&sysparm_display_value=true
Step 2: Extract Data from Utility Invoices
Process utility invoice data to extract environmental metrics.
Retrieve invoice attachments:
Tool: SN-Query-Table
Parameters:
table_name: sys_attachment
query: table_nameLIKEesg^ORtable_nameLIKEutility^ORtable_nameLIKEinvoice^content_typeLIKEpdf
fields: sys_id,file_name,table_name,table_sys_id,content_type,size_bytes,sys_created_on
limit: 50
order_by_desc: sys_created_on
Parse and record extracted energy data:
Tool: SN-Create-Record
Parameters:
table_name: sn_esg_data_point
fields:
metric: [energy_metric_sys_id]
value: 45230
date: 2026-02-28
source_document: "February 2026 Electric Utility Invoice - Building A"
location: [location_sys_id]
verified: false
notes: "Extracted from utility invoice. 45,230 kWh electricity consumption."
Step 3: Calculate Carbon Emissions
Compute Scope 1, 2, and 3 emissions from source data:
Tool: SN-Execute-Background-Script
Parameters:
script: |
// EPA emission factors (2025 US average)
var EMISSION_FACTORS = {
electricity_kwh: 0.000386, // metric tons CO2e per kWh (US avg grid)
natural_gas_therm: 0.005302, // metric tons CO2e per therm
diesel_gallon: 0.010180, // metric tons CO2e per gallon
gasoline_gallon: 0.008887, // metric tons CO2e per gallon
propane_gallon: 0.005740 // metric tons CO2e per gallon
};
var period = '2026-Q1';
var emissions = {
period: period,
scope1: { total: 0, sources: {} },
scope2: { total: 0, sources: {} },
scope3: { total: 0, sources: {} },
total_co2e: 0,
unit: 'metric tons CO2e'
};
// Query energy data points for the period
var dp = new GlideRecord('sn_esg_data_point');
dp.addQuery('date', '>=', '2026-01-01');
dp.addQuery('date', '<=', '2026-03-31');
dp.query();
while (dp.next()) {
var metricRec = new GlideRecord('sn_esg_metric');
metricRec.get(dp.metric.toString());
var metricName = metricRec.metric_name.toString().toLowerCase();
var value = parseFloat(dp.value.toString()) || 0;
var scope = metricRec.scope.toString();
var co2e = 0;
if (metricName.match(/electricity/)) co2e = value * EMISSION_FACTORS.electricity_kwh;
else if (metricName.match(/natural gas/)) co2e = value * EMISSION_FACTORS.natural_gas_therm;
else if (metricName.match(/diesel/)) co2e = value * EMISSION_FACTORS.diesel_gallon;
else if (metricName.match(/gasoline/)) co2e = value * EMISSION_FACTORS.gasoline_gallon;
if (scope == '1') {
emissions.scope1.total += co2e;
emissions.scope1.sources[metricName] = (emissions.scope1.sources[metricName] || 0) + co2e;
} else if (scope == '2') {
emissions.scope2.total += co2e;
emissions.scope2.sources[metricName] = (emissions.scope2.sources[metricName] || 0) + co2e;
} else {
emissions.scope3.total += co2e;
emissions.scope3.sources[metricName] = (emissions.scope3.sources[metricName] || 0) + co2e;
}
}
emissions.scope1.total = Math.round(emissions.scope1.total * 100) / 100;
emissions.scope2.total = Math.round(emissions.scope2.total * 100) / 100;
emissions.scope3.total = Math.round(emissions.scope3.total * 100) / 100;
emissions.total_co2e = emissions.scope1.total + emissions.scope2.total + emissions.scope3.total;
gs.info('EMISSIONS CALCULATION:\n' + JSON.stringify(emissions, null, 2));
description: "ESG: Calculate GHG emissions by scope from energy data points"
Step 4: Assess Disclosure Completeness
Check which framework disclosures are complete vs. gaps:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var frameworks = ['GRI', 'SASB', 'TCFD', 'CDP'];
var completeness = { reporting_period: '2025', frameworks: {} };
for (var f = 0; f < frameworks.length; f++) {
var fw = frameworks[f];
completeness.frameworks[fw] = { total: 0, complete: 0, in_progress: 0, not_started: 0, gaps: [] };
var disc = new GlideRecord('sn_esg_disclosure');
disc.addQuery('framework.name', fw);
disc.addQuery('reporting_period', '2025');
disc.query();
while (disc.next()) {
completeness.frameworks[fw].total++;
var status = disc.status.toString().toLowerCase();
if (status == 'complete' || status == 'submitted') {
completeness.frameworks[fw].complete++;
} else if (status == 'in_progress' || status == 'draft') {
completeness.frameworks[fw].in_progress++;
} else {
completeness.frameworks[fw].not_started++;
completeness.frameworks[fw].gaps.push({
disclosure_id: disc.disclosure_id.toString(),
description: disc.short_description.toString()
});
}
}
}
gs.info('DISCLOSURE COMPLETENESS:\n' + JSON.stringify(completeness, null, 2));
description: "ESG: Assess disclosure completeness across ESG frameworks"
Step 5: Generate ESG Performance Dashboard Data
Compile trend data for executive reporting:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var dashboard = {
generated_date: new GlideDateTime().toString(),
environmental: {
total_emissions_ytd: 0,
emissions_vs_target: '',
energy_consumption_kwh: 0,
renewable_percentage: 0,
waste_diverted_percentage: 0,
water_usage_gallons: 0
},
yoy_comparison: {},
by_location: {},
data_quality: { verified: 0, unverified: 0, missing: 0 }
};
// Aggregate YTD metrics by category
var categories = {
'emissions': 'total_emissions_ytd',
'energy': 'energy_consumption_kwh',
'water': 'water_usage_gallons'
};
var metric = new GlideRecord('sn_esg_metric');
metric.addQuery('category', 'environmental');
metric.addQuery('active', true);
metric.query();
while (metric.next()) {
var loc = metric.location.getDisplayValue() || 'Unknown';
if (!dashboard.by_location[loc]) dashboard.by_location[loc] = { emissions: 0, energy: 0 };
var val = parseFloat(metric.value.toString()) || 0;
var mName = metric.metric_name.toString().toLowerCase();
if (mName.match(/emission|co2|ghg/)) {
dashboard.environmental.total_emissions_ytd += val;
dashboard.by_location[loc].emissions += val;
}
if (mName.match(/energy|electricity|kwh/)) {
dashboard.environmental.energy_consumption_kwh += val;
dashboard.by_location[loc].energy += val;
}
}
// Data quality check
var dp = new GlideAggregate('sn_esg_data_point');
dp.addQuery('verified', true);
dp.addAggregate('COUNT');
dp.query();
if (dp.next()) dashboard.data_quality.verified = parseInt(dp.getAggregate('COUNT'));
var dpUnverified = new GlideAggregate('sn_esg_data_point');
dpUnverified.addQuery('verified', false);
dpUnverified.addAggregate('COUNT');
dpUnverified.query();
if (dpUnverified.next()) dashboard.data_quality.unverified = parseInt(dpUnverified.getAggregate('COUNT'));
gs.info('ESG DASHBOARD DATA:\n' + JSON.stringify(dashboard, null, 2));
description: "ESG: Generate environmental performance dashboard data"
Step 6: Update Metrics from Extracted Data
Record newly extracted metrics back to the ESG module:
Tool: SN-Update-Record
Parameters:
table_name: sn_esg_metric
sys_id: [metric_sys_id]
data:
value: 1245.6
last_updated: 2026-03-19
data_source: "Utility invoices Q1 2026 - Buildings A, B, C"
work_notes: "Updated from Q1 utility invoice extraction. Previous value: 1180.2. Increase of 5.5% due to expanded Building C operations."
Tool Usage
| Operation | MCP Tool | REST Endpoint |
|---|---|---|
| Query Metrics | SN-Query-Table | GET /api/now/table/sn_esg_metric |
| Query Disclosures | SN-Query-Table | GET /api/now/table/sn_esg_disclosure |
| Query Frameworks | SN-Query-Table | GET /api/now/table/sn_esg_framework |
| Create Data Points | SN-Create-Record | POST /api/now/table/sn_esg_data_point |
| Update Metrics | SN-Update-Record | PATCH /api/now/table/sn_esg_metric |
| Emissions Calculation | SN-Execute-Background-Script | POST /api/now/table/sys_trigger |
| Search Documents | SN-Natural-Language-Search | N/A |
Best Practices
- Source Traceability: Always link data points to their source documents (invoices, reports) for audit trail
- Emission Factor Currency: Update emission factors annually; use regional grid factors rather than national averages when available
- Verification Workflow: Mark all extracted data as unverified until reviewed by the sustainability team
- Scope Accuracy: Carefully classify emissions by scope per GHG Protocol; market-based vs. location-based for Scope 2
- Unit Consistency: Standardize units across facilities (kWh, metric tons CO2e, gallons) before aggregation
- Gap Documentation: Document data gaps explicitly; estimated values should be flagged with methodology notes
- Framework Alignment: Map each metric to the specific GRI Standard, SASB topic, or TCFD recommendation it supports
- Materiality Focus: Prioritize metrics that align with your organization's materiality assessment results
Troubleshooting
ESG Metric Table Not Found
Symptom: Query against sn_esg_metric returns a table-not-found error
Cause: The ESG Management plugin may not be activated, or the table name may differ by version
Solution: Query sys_db_object with nameLIKEesg to find available ESG tables. Check if com.sn_esg plugin is active.
Emission Factors Produce Incorrect Results
Symptom: Calculated emissions seem unreasonably high or low Cause: Unit mismatch between input data and emission factor (e.g., MWh vs. kWh, therms vs. MMBtu) Solution: Verify the unit field on both the metric and data point records. Convert units before applying emission factors.
Disclosure Framework Records Missing
Symptom: No disclosure records found for GRI, SASB, or TCFD Cause: Framework disclosure templates must be loaded via the ESG module setup; they are not auto-populated Solution: Navigate to ESG Management > Frameworks in the ServiceNow UI and import the relevant framework templates.
Examples
Example 1: Monthly Utility Invoice Processing
Scenario: Sustainability analyst processes monthly electricity and gas invoices
Tool: SN-Create-Record
Parameters:
table_name: sn_esg_data_point
fields:
metric: [electricity_metric_sys_id]
value: 125400
date: 2026-02-28
source_document: "ConEd Invoice #INV-2026-0228 - HQ Building"
location: [hq_location_sys_id]
verified: false
notes: "125,400 kWh. Rate: $0.14/kWh. Total: $17,556. Demand charge: 450 kW peak."
Result: Data point recorded, Scope 2 emissions auto-calculated at 48.4 metric tons CO2e.
Example 2: Annual CDP Disclosure Preparation
Scenario: ESG manager needs to identify gaps in CDP Climate Change questionnaire
Tool: SN-Query-Table
Parameters:
table_name: sn_esg_disclosure
query: framework.nameLIKECDP^reporting_period=2025^status!=complete
fields: disclosure_id,short_description,status,response,evidence
limit: 100
Result: 14 of 82 CDP disclosures incomplete. Critical gaps: Scope 3 Category 6 (Business Travel), Scope 3 Category 7 (Employee Commuting), Climate-related targets validation.
Related Skills
grc/issue-summarization- GRC issue analysis for ESG compliance findingsgrc/risk-assessment-summarization- Climate risk assessment analysisgrc/regulatory-alert-analysis- ESG regulatory change trackingdocument/document-extraction- Extract data from utility invoices and reportsreporting/executive-dashboard- Build ESG executive dashboards