Custom Emission Factors Guide
Custom emission factors allow you to use supplier-verified emission data instead of generic database factors, significantly improving the accuracy of your carbon accounting.
Use custom emission factors only when you have verified, supplier-specific data. Incorrect factors can significantly impact your footprint accuracy.
When to Use Custom Emission Factors
β
Use Custom Factors When:
You have supplier EPDs (Environmental Product Declarations)
Suppliers provide verified LCA data for their products. Example : Your aluminum supplier provides an EPD showing their recycled aluminum has 2.15 kg CO2e/kg instead of the generic 8.5 kg CO2e/kg.Accuracy improvement : Β±5-15% vs Β±30-50% with generic factors
You have renewable energy PPAs (Power Purchase Agreements)
You purchase renewable energy with specific grid mix documentation. Example : 100% wind energy PPA with zero emissions vs generic grid electricity at 0.38 kg CO2e/kWh.Accuracy improvement : Eliminates Scope 2 uncertainty
Specific processes differ significantly from standards
Your supplier uses unique processes that differ from industry averages. Example : Waste incineration with energy recovery has net lower emissions than standard incineration.Accuracy improvement : Β±10-20% vs Β±40-60%
Regulatory requirements mandate specific methodologies
Regulations require specific calculation methods or factors. Example : EU requires specific factors for certain industries under CBAM.Accuracy improvement : Compliance-grade accuracy
β Donβt Use Custom Factors When:
Youβre estimating or guessing values (use standard factors instead)
Data is not from verified sources (EPDs, audited LCAs)
You want to artificially lower emissions (greenwashing)
Standard Dcycle factors are appropriate and available
Understanding the Structure
Custom emission factors are organized in a two-level hierarchy:
Custom Emission Group (Category)
ββ Custom Emission Factor 1
ββ Custom Emission Factor 2
ββ Custom Emission Factor 3
Custom Emission Groups
Groups organize related factors by category:
Category Use For Example purchases Supplier-specific product factors βSupplier ABC Materials 2024β wastes Custom waste treatment factors βLocal Recycling Facilityβ energy Renewable energy contracts βWind Farm PPA 2024-2034β
Custom Emission Factors
Individual factors within a group with:
Emission values for each GHG (CO2, CH4, N2O, etc.)
Uncertainty grade (0-100%)
Validity period
Documentation reference
Category-specific fields (renewable %, hazardous, etc.)
Step-by-Step Implementation
Using the Dcycle App? You can also create custom emission factors through our web interface:
Step 1: Get Required Unit IDs
First, find the unit ID for your factor:
import requests
import os
headers = {
"Authorization" : f "Bearer { os.getenv( 'DCYCLE_API_KEY' ) } " ,
"x-organization-id" : os.getenv( "DCYCLE_ORG_ID" ),
"x-user-id" : os.getenv( "DCYCLE_USER_ID" )
}
# Get available units
units = requests.get(
"https://api.dcycle.io/api/v1/units" ,
headers = headers,
params = { "page" : 1 , "size" : 100 }
).json()
# Find kilogram unit
kg_unit = next (u for u in units[ 'items' ] if u[ 'abbreviation' ] == 'kg' )
print ( f "Kilogram unit ID: { kg_unit[ 'id' ] } " )
Step 2: Create a Custom Emission Group
Create a group to organize your factors:
# Create group for supplier materials
group_data = {
"name" : "Supplier ABC Materials 2024" ,
"description" : "EPD-verified emission factors from Supplier ABC. All factors third-party verified by Bureau Veritas. Valid for 2024." ,
"category" : "purchases" , # purchases, wastes, or energy
"ghg_type" : 1 # 1=fossil, 2=biogenic, 3=mixed
}
group = requests.post(
"https://api.dcycle.io/api/v1/custom_emission_groups" ,
headers = headers,
json = group_data
).json()
group_id = group[ 'id' ]
print ( f "β
Created group: { group_id } " )
Step 3: Add Custom Emission Factors
Add individual factors to the group:
# Create custom factor for recycled aluminum
factor_data = {
"ef_name" : "Recycled Aluminum Sheet - Supplier ABC" ,
"unit_id" : kg_unit[ 'id' ],
"factor_uploaded_by" : "[email protected] " ,
"tag" : "advanced" , # "simple" or "advanced"
"uncertainty_grade" : 12 , # 0-100% (lower = more certain)
"factor_start_date" : "2024-01-01" ,
"factor_end_date" : "2024-12-31" ,
"additional_docs" : "EPD No. ABC-2024-001, Bureau Veritas verified, dated 2024-01-15. Cradle-to-gate LCA." ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 2.15 },
{ "gas_type" : "CH4" , "value" : 0.008 },
{ "gas_type" : "N2O" , "value" : 0.002 }
],
"recycled" : True # For material factors
}
factor = requests.post(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { group_id } " ,
headers = headers,
json = factor_data
).json()
factor_id = factor[ 'id' ]
print ( f "β
Created factor: { factor_id } " )
print ( f " Total CO2e: {sum (v[ 'value' ] for v in factor[ 'emission_factor_values' ]) } kg/kg" )
Step 4: Use the Custom Factor
Reference the factor when tracking purchases:
# Track purchase using custom factor
purchase_data = {
"name" : "Aluminum sheets from Supplier ABC" ,
"custom_emission_factor_id" : factor_id, # Use custom factor
"quantity" : 1000 ,
"unit_id" : kg_unit[ 'id' ],
"purchase_date" : "2024-03-15" ,
"supplier_id" : "supplier-abc-uuid" # Optional
}
purchase = requests.post(
"https://api.dcycle.io/api/v1/purchases" ,
headers = headers,
json = purchase_data
).json()
print ( f "β
Purchase tracked" )
print ( f " Quantity: { purchase[ 'quantity' ] } kg" )
print ( f " Emissions: { purchase[ 'co2e' ] } kg CO2e" )
print ( f " Used custom factor: { purchase[ 'emission_factor_used' ] } " )
Real-World Examples
Example 1: Supplier-Specific Product Portfolio
Track a complete product portfolio from a single supplier:
# Create group
group = requests.post(
"https://api.dcycle.io/api/v1/custom_emission_groups" ,
headers = headers,
json = {
"name" : "GreenTech Industries 2024" ,
"description" : "Complete product portfolio with verified EPDs. Updated quarterly." ,
"category" : "purchases" ,
"ghg_type" : 1
}
).json()
# Add multiple products
products = [
{
"ef_name" : "Recycled Aluminum Sheet" ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 2.15 },
{ "gas_type" : "CH4" , "value" : 0.008 },
{ "gas_type" : "N2O" , "value" : 0.002 }
],
"recycled" : True ,
"uncertainty_grade" : 12 ,
"additional_docs" : "EPD-GT-AL-2024"
},
{
"ef_name" : "Low-Carbon Steel Beam" ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 1.85 },
{ "gas_type" : "CH4" , "value" : 0.005 },
{ "gas_type" : "N2O" , "value" : 0.001 }
],
"recycled" : False ,
"uncertainty_grade" : 18 ,
"additional_docs" : "EPD-GT-ST-2024"
},
{
"ef_name" : "Recycled Plastic Granules" ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 1.45 },
{ "gas_type" : "CH4" , "value" : 0.012 },
{ "gas_type" : "N2O" , "value" : 0.003 }
],
"recycled" : True ,
"uncertainty_grade" : 20 ,
"additional_docs" : "EPD-GT-PL-2024"
}
]
for product in products:
product.update({
"unit_id" : kg_unit[ 'id' ],
"factor_uploaded_by" : "[email protected] " ,
"tag" : "advanced" ,
"factor_start_date" : "2024-01-01" ,
"factor_end_date" : "2024-12-31"
})
factor = requests.post(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { group[ 'id' ] } " ,
headers = headers,
json = product
).json()
print ( f "β
Added: { factor[ 'ef_name' ] } " )
Example 2: Renewable Energy PPA
Track a Power Purchase Agreement for wind energy:
# Create energy group
ppa_group = requests.post(
"https://api.dcycle.io/api/v1/custom_emission_groups" ,
headers = headers,
json = {
"name" : "Wind Farm PPA 2024-2034" ,
"description" : "10-year wind energy PPA. Contract #PPA-WIND-2024-001. 100 % r enewable allocation." ,
"category" : "energy" ,
"ghg_type" : 2 # Biogenic (renewable)
}
).json()
# Get kWh unit
kwh_unit = next (u for u in units[ 'items' ] if u[ 'abbreviation' ] == 'kWh' )
# Create zero-emission factor
ppa_factor = requests.post(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { ppa_group[ 'id' ] } " ,
headers = headers,
json = {
"ef_name" : "Wind Farm PPA - Northern Region" ,
"unit_id" : kwh_unit[ 'id' ],
"factor_uploaded_by" : "[email protected] " ,
"tag" : "advanced" ,
"uncertainty_grade" : 5 , # Very low (contract guaranteed)
"factor_start_date" : "2024-01-01" ,
"factor_end_date" : "2034-12-31" , # 10-year contract
"additional_docs" : "PPA Contract #PPA-WIND-2024-001, signed 2023-11-15" ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 0.0 } # Zero direct emissions
],
"renewable_percentage" : 100.0
}
).json()
print ( f "β
PPA factor created: { ppa_factor[ 'id' ] } " )
Example 3: Waste Treatment Facility
Custom factors for a specific waste treatment facility:
# Create waste group
waste_group = requests.post(
"https://api.dcycle.io/api/v1/custom_emission_groups" ,
headers = headers,
json = {
"name" : "Regional Waste Facility 2024" ,
"description" : "Custom factors for local waste treatment with energy recovery. Facility report Q4 2023." ,
"category" : "wastes" ,
"ghg_type" : 3 # Mixed (fossil + biogenic)
}
).json()
# Incineration with energy recovery
waste_factor = requests.post(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { waste_group[ 'id' ] } " ,
headers = headers,
json = {
"ef_name" : "Mixed Waste Incineration with Energy Recovery" ,
"unit_id" : kg_unit[ 'id' ],
"factor_uploaded_by" : "[email protected] " ,
"tag" : "advanced" ,
"uncertainty_grade" : 25 ,
"factor_start_date" : "2024-01-01" ,
"factor_end_date" : "2024-12-31" ,
"additional_docs" : "Facility report Q4 2023. Includes energy credit allocation." ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 0.45 }, # Net after energy recovery
{ "gas_type" : "CH4" , "value" : 0.002 },
{ "gas_type" : "N2O" , "value" : 0.015 } # Higher from incineration
],
"hazardous" : False ,
"low_code" : "19 12 10" , # LER code for combustible waste
"rd_code" : "R1" # Recovery operation with energy
}
).json()
print ( f "β
Waste factor created" )
Data Quality and Uncertainty
Uncertainty Grades
Track confidence in your data:
Grade Confidence When to Use 0-20% Very High Supplier-verified EPD, third-party audited 21-40% High Industry-specific studies, peer-reviewed 41-60% Medium Reasonable estimates, documented assumptions 61-80% Low Limited data, significant assumptions 81-100% Very Low Rough estimates (improve ASAP)
# Example: Track uncertainty over time
factors_by_uncertainty = {
"high_confidence" : [], # < 20%
"medium_confidence" : [], # 20-50%
"low_confidence" : [] # > 50%
}
for factor in all_factors:
ug = factor.get( 'uncertainty_grade' , 100 )
if ug < 20 :
factors_by_uncertainty[ 'high_confidence' ].append(factor)
elif ug < 50 :
factors_by_uncertainty[ 'medium_confidence' ].append(factor)
else :
factors_by_uncertainty[ 'low_confidence' ].append(factor)
# Prioritize improving low confidence factors
print ( f "Improve these {len (factors_by_uncertainty[ 'low_confidence' ]) } factors:" )
for factor in factors_by_uncertainty[ 'low_confidence' ]:
print ( f " - { factor[ 'ef_name' ] } : { factor[ 'uncertainty_grade' ] } %" )
Documentation Best Practices
Always document your sources:
# β
Good documentation
"additional_docs" : """
EPD No. ABC-2024-001
Third-party verified: Bureau Veritas
Verification date: 2024-01-15
System boundary: Cradle-to-gate
Methodology: ISO 14040/14044
Functional unit: 1 kg of product
Allocation: Economic allocation
Data quality: Primary data from production 2023
Geographic scope: European production
"""
# β Poor documentation
"additional_docs" : "supplier data"
Managing Custom Factors
List All Factors in a Group
group_id = "group-uuid"
factors = requests.get(
f "https://api.dcycle.io/api/v1/custom_emission_factors/list/ { group_id } " ,
headers = headers,
params = { "page" : 1 , "size" : 50 }
).json()
print ( f "Group has { factors[ 'total' ] } factors:" )
for factor in factors[ 'items' ]:
total_co2e = sum (v[ 'value' ] for v in factor[ 'emission_factor_values' ])
print ( f " - { factor[ 'ef_name' ] } : { total_co2e } kg CO2e/ { factor[ 'unit_id' ] } " )
Update a Factor
# Get current factor
factor = requests.get(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { factor_id } " ,
headers = headers
).json()
# Update with new EPD data
update_data = {
"factor_uploaded_by" : "[email protected] " ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 2.05 }, # Updated value
{ "gas_type" : "CH4" , "value" : 0.007 },
{ "gas_type" : "N2O" , "value" : 0.002 }
],
"additional_docs" : f " { factor[ 'additional_docs' ] } | Updated 2024-06-15 with Q2 2024 EPD"
}
updated = requests.patch(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { factor_id } " ,
headers = headers,
json = update_data
).json()
print ( f "β
Factor updated" )
Archive Old Factors
Instead of deleting, mark as outdated:
# Delete old factor
requests.delete(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { old_factor_id } " ,
headers = headers
)
# Create new factor with updated data
new_factor = requests.post(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { group_id } " ,
headers = headers,
json = {
** new_factor_data,
"ef_name" : "Product XYZ - Supplier ABC (2024 Update)" ,
"additional_docs" : "Supersedes factor-old-uuid. Updated Q2 2024."
}
).json()
Validation and Quality Checks
Validate Before Creating
def validate_custom_factor (data):
"""Validate custom factor data"""
# Required fields
assert data.get( 'ef_name' ), "Name required"
assert data.get( 'unit_id' ), "Unit required"
assert data.get( 'emission_factor_values' ), "Emission values required"
# Check CO2 is present
gases = [v[ 'gas_type' ] for v in data[ 'emission_factor_values' ]]
assert 'CO2' in gases or 'co2e' in gases, "CO2 or co2e required"
# Check tag matches emission values
if data.get( 'tag' ) == 'advanced' :
assert len (data[ 'emission_factor_values' ]) >= 3 , "Advanced tag requires 3+ gases"
# Uncertainty check
if data.get( 'uncertainty_grade' , 0 ) > 50 :
print ( f "β οΈ Warning: High uncertainty ( { data[ 'uncertainty_grade' ] } %)" )
# Documentation check
if not data.get( 'additional_docs' ):
print ( f "β οΈ Warning: No documentation provided" )
return True
Compare with Standard Factors
# Calculate difference from standard factor
custom_co2e = sum (v[ 'value' ] for v in custom_factor[ 'emission_factor_values' ])
standard_co2e = 8.5 # Generic aluminum factor
difference_pct = ((custom_co2e - standard_co2e) / standard_co2e) * 100
print ( f "Custom factor: { custom_co2e } kg CO2e/kg" )
print ( f "Standard factor: { standard_co2e } kg CO2e/kg" )
print ( f "Difference: { difference_pct :+.1f } %" )
if abs (difference_pct) > 50 :
print ( "β οΈ Warning: >50 % d ifference from standard. Verify data." )
Troubleshooting
Issue: Factor Not Applied
# Check if factor exists and is valid
factor = requests.get(
f "https://api.dcycle.io/api/v1/custom_emission_factors/ { factor_id } " ,
headers = headers
).json()
# Check dates
from datetime import date
today = date.today()
start = date.fromisoformat(factor[ 'factor_start_date' ])
end = date.fromisoformat(factor[ 'factor_end_date' ])
if not (start <= today <= end):
print ( f "β Factor not valid today ( { today } )" )
print ( f " Valid: { start } to { end } " )
Issue: Validation Error on Creation
# Common errors:
# 1. Missing CO2 value
"emission_factor_values" : [
{ "gas_type" : "CH4" , "value" : 0.008 } # β Missing CO2
]
# 2. Wrong tag
"tag" : "simple" ,
"emission_factor_values" : [
{ "gas_type" : "CO2" , "value" : 2.15 },
{ "gas_type" : "CH4" , "value" : 0.008 } # β Simple needs only co2e
]
# 3. Invalid uncertainty grade
"uncertainty_grade" : 150 # β Must be 0-100
Next Steps