Skip to main content

Understanding Scope 3 Category 7

Employee commuting covers emissions from the transportation of employees between their homes and worksites in vehicles not owned or operated by your organization. According to the GHG Protocol Scope 3 Standard, Category 7 includes:
  • Daily commuting: Regular home-to-work travel
  • All transport modes: Car, public transit, cycling, walking
  • Remote work: Zero emissions for work-from-home days
  • Carpooling: Shared vehicle emissions (divided among passengers)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              SCOPE 3 CATEGORY 7: Employee Commuting                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  EMPLOYEE HOMES                               WORKPLACE                     β”‚
β”‚  ──────────────────                           ──────────                    β”‚
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚   🏠 Home    │◄─── πŸš— Car ────────────►   β”‚   🏒 Office  β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚              β”‚               β”‚
β”‚                                              β”‚              β”‚               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”‚              β”‚               β”‚
β”‚  β”‚   🏠 Home    │◄─── πŸš‚ Train ──────────►   β”‚              β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚              β”‚               β”‚
β”‚                                              β”‚              β”‚               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”‚              β”‚               β”‚
β”‚  β”‚   🏠 Home    │◄─── 🚌 Bus ────────────►   β”‚              β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚              β”‚               β”‚
β”‚                                              β”‚              β”‚               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”‚              β”‚               β”‚
β”‚  β”‚   🏠 Home    │◄─── 🚲 Bike ───────────►   β”‚              β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚              β”‚               β”‚
β”‚                                              β”‚              β”‚               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”‚              β”‚               β”‚
β”‚  β”‚   🏠 Home    │──── πŸ’» Remote ───────────  β”‚   (0 km)     β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
β”‚                                                                             β”‚
β”‚  DAILY ROUND TRIP:                                                          β”‚
β”‚  β€’ Distance (km) Γ— 2 (round trip)                                           β”‚
β”‚  β€’ Γ— Working days per week                                                  β”‚
β”‚  β€’ Γ— Emission factor (by transport mode)                                    β”‚
β”‚                                                                             β”‚
β”‚  INCLUDED:                             NOT INCLUDED:                        β”‚
β”‚  β€’ Daily commute                       β€’ Business travel (Category 6)       β”‚
β”‚  β€’ All transport modes                 β€’ Company vehicles (Scope 1)         β”‚
β”‚  β€’ Remote work tracking                β€’ Customer/visitor travel            β”‚
β”‚  β€’ Carpooling emissions                                                     β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Category 7 vs Category 6
  • Category 7 (Employee Commuting): Daily travel between home and work
  • Category 6 (Business Travel): Trips for business purposes (meetings, conferences, site visits)

Prerequisites

Before starting, ensure you have:
Using the Dcycle App?You can track employee commuting through our web interface:
  • Send employee surveys (ES) - Collect data via email
  • Manual entry for individual employees
  • CSV bulk upload for HR data

Data Map: Category 7 Requirements Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   CATEGORY 7 DATA REQUIREMENTS OVERVIEW                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ EMPLOYEE RECORD                                                                 β”‚   β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β”‚  Required Fields              Optional Fields                                   β”‚   β”‚
β”‚  β”‚  ──────────────────           ──────────────────                                β”‚   β”‚
β”‚  β”‚  β€’ origin OR total_km         β€’ email                                           β”‚   β”‚
β”‚  β”‚  β€’ destination OR total_km    β€’ name                                            β”‚   β”‚
β”‚  β”‚  β€’ transport_type             β€’ vehicle_size                                    β”‚   β”‚
β”‚  β”‚  β€’ weekly_travels             β€’ fuel_type                                       β”‚   β”‚
β”‚  β”‚                               β€’ renewable_energy                                β”‚   β”‚
β”‚  β”‚                               β€’ carpool (true/false)                            β”‚   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ COMMUTING PERIOD (Employee Historic)                                            β”‚   β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β”‚  Required Fields              Optional Fields                                   β”‚   β”‚
β”‚  β”‚  ──────────────────           ──────────────────                                β”‚   β”‚
β”‚  β”‚  β€’ commuting_type             β€’ situation                                       β”‚   β”‚
β”‚  β”‚    ("in_itinere")                                                               β”‚   β”‚
β”‚  β”‚  β€’ start_date                                                                   β”‚   β”‚
β”‚  β”‚  β€’ end_date                                                                     β”‚   β”‚
β”‚  β”‚  β€’ daily_trips (default: 1)                                                     β”‚   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ CALCULATION FLOW                                                                β”‚   β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β”‚  Origin + Destination ──► Distance (km) [one-way]                               β”‚   β”‚
β”‚  β”‚                                β”‚                                                β”‚   β”‚
β”‚  β”‚  Weekly Travels ──────────────┼──► Working days in period                       β”‚   β”‚
β”‚  β”‚                               β”‚                                                 β”‚   β”‚
β”‚  β”‚  Transport Type ──────────────┼──► Emission Factor (kg COβ‚‚e/km)                 β”‚   β”‚
β”‚  β”‚                               β”‚                                                 β”‚   β”‚
β”‚  β”‚  COβ‚‚e = Distance Γ— Days Γ— Daily_Trips Γ— EF Γ— 2 (round trip)                     β”‚   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β”‚  If carpool: COβ‚‚e Γ· 3 (carpool factor)                                          β”‚   β”‚
β”‚  β”‚                                                                                 β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Weekly Travels (Working Days)

The weekly_travels field defines which days of the week the employee commutes:
DayValueDescription
Monday0Included if present in array
Tuesday1Included if present in array
Wednesday2Included if present in array
Thursday3Included if present in array
Friday4Included if present in array
Saturday5Included if present in array
Sunday6Included if present in array
Examples:
Patternweekly_travelsDescription
Full week (Mon-Fri)[0, 1, 2, 3, 4]Traditional 5-day week
3 days/week[0, 2, 4]Mon, Wed, Fri only
Hybrid (2 days)[1, 3]Tue, Thu in office
Full remote[]Empty = no commuting
Remote Work / TeleworkSet weekly_travels: [] (empty array) for fully remote employees. Dcycle will calculate zero commuting emissions for these employees.

Transport Types

Transport TypeDescriptionTypical EF Range
carPersonal vehicle0.1-0.2 kg COβ‚‚e/km
busPublic bus0.05-0.1 kg COβ‚‚e/km
trainCommuter rail0.03-0.05 kg COβ‚‚e/km
metroUrban subway0.02-0.04 kg COβ‚‚e/km
tramLight rail0.02-0.04 kg COβ‚‚e/km
motorbikeMotorcycle0.08-0.12 kg COβ‚‚e/km
bicycleCycling0 kg COβ‚‚e/km
walkWalking0 kg COβ‚‚e/km
Vehicle options for cars:
Vehicle SizeFuel TypeDescription
smallpetrol, diesel, electric, hybridCompact cars
mediumpetrol, diesel, electric, hybridSedans
largepetrol, diesel, electric, hybridSUVs
CarpoolingWhen carpool: true, emissions are divided by 3 (average carpool occupancy). This encourages shared transportation and accurately reflects the lower per-person emissions.

Emission Factor Sources

Dcycle uses commuting emission factors from Ecoinvent:
Ecoinvent 3.8+ Cut-off
  • Lifecycle emission factors by transport mode
  • Regional variations where available
  • Covers cars, public transit, and active transport
  • Well-to-Wheel (WTW) factors including fuel production
Google Maps API:
  • Actual road distances between home and work
  • Accounts for real routes, not straight-line distance
  • If origin/destination unavailable, use total_km directly

Step 1: Create Employee Records

FieldTypeRequiredDescriptionExample
originstring⚠️Home address/city"Madrid, Spain"
destinationstring⚠️Office address"Company HQ, Madrid"
total_kmnumber⚠️One-way distance15
transport_typestringβœ…Commute mode"car"
weekly_travelsarrayβœ…Days in office [0-6][0, 1, 2, 3, 4]
emailstring❌Employee email"[email protected]"
namestring❌Employee name"John Smith"
vehicle_sizestring❌For cars"medium"
fuel_typestring❌For cars"petrol"
carpoolboolean❌Shared vehiclefalse
⚠️ Conditional requirements:
  • Either origin + destination OR total_km must be provided
Where to get this data:
  • Home location: HR records, employee surveys
  • Transport mode: Employee surveys
  • Working days: HR/scheduling systems
Track individual employee commuting:
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Example: Employee commuting by car (5 days/week)
employee = {
    "email": "[email protected]",
    "name": "John Smith",
    "origin": "Residential Area, Madrid",
    "destination": "Company HQ, Madrid Business District",
    "transport_type": "car",
    "vehicle_size": "medium",
    "fuel_type": "petrol",
    "weekly_travels": [0, 1, 2, 3, 4],  # Mon-Fri
    "carpool": False,
}

response = requests.post(
    "https://api.dcycle.io/api/v1/employees",
    headers=headers,
    json=employee
).json()

print(f"βœ… Employee created")
print(f"   ID: {response['id']}")
print(f"   Email: {employee['email']}")
print(f"   Commute: {employee['origin']} β†’ {employee['destination']}")
print(f"   Transport: {employee['transport_type']}")
print(f"   Days/week: {len(employee['weekly_travels'])}")

# Create commuting period
employee_id = response['id']

commuting_period = {
    "employee_id": employee_id,
    "commuting_type": "in_itinere",  # Home-work commute
    "start_date": "2024-01-01",
    "end_date": "2024-12-31",
    "daily_trips": 1,  # 1 round trip per day
    "origin": employee['origin'],
    "destination": employee['destination'],
    "total_km": 15,  # One-way distance
    "transport_type": employee['transport_type'],
    "vehicle_size": employee.get('vehicle_size'),
    "fuel_type": employee.get('fuel_type'),
    "weekly_travels": employee['weekly_travels'],
    "carpool": employee.get('carpool', False),
}

period_response = requests.post(
    "https://api.dcycle.io/api/v1/employees_historic",
    headers=headers,
    json=commuting_period
).json()

print(f"   Period: {commuting_period['start_date']} to {commuting_period['end_date']}")
print(f"   Distance: {commuting_period['total_km']} km (one-way)")
print(f"   COβ‚‚e: {period_response.get('co2e', 'Calculating...')} kg")

Common Commuting Scenarios

# Example employees with different commuting patterns

employees = [
    # Full-time office worker (car)
    {
        "email": "[email protected]",
        "name": "Alice Johnson",
        "total_km": 20,
        "transport_type": "car",
        "vehicle_size": "medium",
        "fuel_type": "diesel",
        "weekly_travels": [0, 1, 2, 3, 4],
        "carpool": False,
    },
    # Hybrid worker (public transit, 3 days)
    {
        "email": "[email protected]",
        "name": "Bob Williams",
        "total_km": 12,
        "transport_type": "train",
        "weekly_travels": [1, 2, 3],  # Tue, Wed, Thu
        "carpool": False,
    },
    # Eco-commuter (bike)
    {
        "email": "[email protected]",
        "name": "Carol Davis",
        "total_km": 5,
        "transport_type": "bicycle",
        "weekly_travels": [0, 1, 2, 3, 4],
        "carpool": False,
    },
    # Remote worker
    {
        "email": "[email protected]",
        "name": "David Brown",
        "total_km": 0,
        "transport_type": "walk",  # Placeholder
        "weekly_travels": [],  # Fully remote
        "carpool": False,
    },
    # Carpooler
    {
        "email": "[email protected]",
        "name": "Emma Wilson",
        "total_km": 25,
        "transport_type": "car",
        "vehicle_size": "large",
        "fuel_type": "petrol",
        "weekly_travels": [0, 1, 2, 3, 4],
        "carpool": True,  # Shares ride with colleagues
    },
    # Electric car commuter
    {
        "email": "[email protected]",
        "name": "Frank Miller",
        "total_km": 30,
        "transport_type": "car",
        "vehicle_size": "medium",
        "fuel_type": "electric",
        "weekly_travels": [0, 1, 2, 3, 4],
        "carpool": False,
    },
]

# Create all employees
for emp in employees:
    response = requests.post(
        "https://api.dcycle.io/api/v1/employees",
        headers=headers,
        json=emp
    ).json()
    
    days = len(emp['weekly_travels'])
    remote = " (Remote)" if days == 0 else ""
    carpool = " πŸš—πŸ‘₯" if emp.get('carpool') else ""
    
    print(f"   {emp['name']}: {emp['transport_type']} | {days} days/week{remote}{carpool}")
    print(f"      Distance: {emp['total_km']} km | COβ‚‚e: {response.get('co2e', 'TBD')} kg/year")

print(f"\nβœ… Created {len(employees)} employee records")

Step 2: Send Employee Surveys

Collect commuting data directly from employees via survey:
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Send survey to employees
survey_request = {
    "emails": [
        "[email protected]",
        "[email protected]",
        "[email protected]",
    ],
    "survey_type": "commuting",
    "message": "Please complete this short survey about your daily commute.",
}

response = requests.post(
    "https://api.dcycle.io/api/v1/employees/survey",
    headers=headers,
    json=survey_request
)

if response.status_code == 200:
    print(f"βœ… Survey sent to {len(survey_request['emails'])} employees")
else:
    print(f"❌ Failed: {response.text}")
Survey QuestionsDcycle’s commuting survey asks employees:
  • Home location (address or postal code)
  • Primary transport mode
  • Vehicle details (if car)
  • Days worked in office per week
  • Carpooling (yes/no)

Step 3: Bulk Upload Employee Data

For organizations with many employees, use CSV upload:

CSV Format

email,name,origin,destination,total_km,transport_type,vehicle_size,fuel_type,weekly_travels,carpool
[email protected],"Alice Johnson",,,20,car,medium,diesel,"[0,1,2,3,4]",false
[email protected],"Bob Williams",,,12,train,,,"[1,2,3]",false
[email protected],"Carol Davis",,,5,bicycle,,,"[0,1,2,3,4]",false
[email protected],"David Brown",,,0,walk,,,"[]",false
[email protected],"Emma Wilson",,,25,car,large,petrol,"[0,1,2,3,4]",true
[email protected],"Frank Miller",,,30,car,medium,electric,"[0,1,2,3,4]",false
CSV Notes:
  • total_km is one-way distance (home to office)
  • weekly_travels use format "[0,1,2,3,4]" (JSON array as string)
  • Empty "[]" for remote workers
  • carpool: true or false

Upload CSV

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"),
}

# Upload CSV file
with open("employee_commuting.csv", "rb") as f:
    files = {"file": ("employee_commuting.csv", f, "text/csv")}
    
    response = requests.post(
        "https://api.dcycle.io/api/v1/employees/bulk/csv",
        headers=headers,
        files=files
    )

if response.status_code == 200:
    result = response.json()
    print(f"βœ… Uploaded {result.get('records_processed', 0)} employee records")
else:
    print(f"❌ Upload failed: {response.text}")

Step 4: Query Category 7 Emissions

Get Employee Commuting Totals

import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID"),
}

# Get all employees
response = requests.get(
    "https://api.dcycle.io/api/v1/employees",
    headers=headers,
    params={
        "enabled": True,
    }
).json()

print(f"πŸ“Š Scope 3 Category 7: Employee Commuting (2024)")
print("=" * 60)

total_employees = len(response.get('items', []))
total_co2e = 0
remote_count = 0

for emp in response.get('items', []):
    co2e = emp.get('co2e', 0) or 0
    total_co2e += co2e
    
    weekly_travels = emp.get('weekly_travels', [])
    if not weekly_travels:
        remote_count += 1

print(f"   Total employees: {total_employees}")
print(f"   Remote workers: {remote_count} ({remote_count/total_employees*100:.0f}%)")
print(f"   Total COβ‚‚e: {total_co2e:,.0f} kg ({total_co2e/1000:.1f} tonnes)")
print(f"   Avg per employee: {total_co2e/total_employees:,.0f} kg/year")

Analyze by Transport Mode

from collections import defaultdict

# Group by transport type
transport_summary = defaultdict(lambda: {"count": 0, "co2e": 0})

for emp in response.get('items', []):
    transport = emp.get('transport_type', 'unknown')
    co2e = emp.get('co2e', 0) or 0
    
    transport_summary[transport]["count"] += 1
    transport_summary[transport]["co2e"] += co2e

print("\nπŸ“Š Category 7 by Transport Mode:")
print("-" * 50)

transport_icons = {
    "car": "πŸš—",
    "train": "πŸš‚",
    "bus": "🚌",
    "metro": "πŸš‡",
    "tram": "🚊",
    "bicycle": "🚲",
    "walk": "🚢",
    "motorbike": "🏍️",
}

for transport, data in sorted(transport_summary.items(), key=lambda x: x[1]['co2e'], reverse=True):
    icon = transport_icons.get(transport, "πŸš€")
    percentage = (data['co2e'] / total_co2e * 100) if total_co2e > 0 else 0
    avg = data['co2e'] / data['count'] if data['count'] > 0 else 0
    
    print(f"   {icon} {transport.capitalize()}:")
    print(f"      Employees: {data['count']}")
    print(f"      Total COβ‚‚e: {data['co2e']:,.0f} kg ({percentage:.1f}%)")
    print(f"      Avg per employee: {avg:,.0f} kg/year")
    print()

Analyze Remote vs Office

# Calculate remote work impact
office_co2e = 0
remote_co2e = 0
office_count = 0
remote_count = 0

for emp in response.get('items', []):
    weekly_travels = emp.get('weekly_travels', [])
    co2e = emp.get('co2e', 0) or 0
    
    if weekly_travels:
        office_co2e += co2e
        office_count += 1
    else:
        remote_co2e += co2e
        remote_count += 1

print("\nπŸ“Š Remote vs Office Impact:")
print("-" * 50)
print(f"   🏒 Office workers: {office_count}")
print(f"      Total COβ‚‚e: {office_co2e:,.0f} kg")
print(f"      Avg per employee: {office_co2e/office_count if office_count else 0:,.0f} kg/year")
print()
print(f"   🏠 Remote workers: {remote_count}")
print(f"      Total COβ‚‚e: {remote_co2e:,.0f} kg (should be ~0)")
print()

# Calculate potential savings
if office_count > 0:
    avg_office_co2e = office_co2e / office_count
    potential_savings_1day = avg_office_co2e / 5  # 1 day remote per week
    potential_savings_2day = avg_office_co2e * 2 / 5  # 2 days remote per week
    
    print(f"   πŸ’‘ Potential savings per employee:")
    print(f"      1 remote day/week: {potential_savings_1day:,.0f} kg/year")
    print(f"      2 remote days/week: {potential_savings_2day:,.0f} kg/year")

Best Practices

1. Track Working Patterns Accurately

# Validate weekly_travels data
def validate_commuting_data(employee):
    """Validate employee commuting data"""
    
    issues = []
    
    weekly_travels = employee.get('weekly_travels', [])
    
    # Check for valid day values
    for day in weekly_travels:
        if day not in range(7):
            issues.append(f"Invalid day value: {day}")
    
    # Check for duplicates
    if len(weekly_travels) != len(set(weekly_travels)):
        issues.append("Duplicate days in weekly_travels")
    
    # Check distance is reasonable
    total_km = employee.get('total_km', 0)
    if total_km and total_km > 150:
        issues.append(f"Unusually high distance: {total_km} km")
    
    return issues

# Validate all employees
for emp in response.get('items', []):
    issues = validate_commuting_data(emp)
    if issues:
        print(f"⚠️ {emp.get('email')}: {', '.join(issues)}")

2. Encourage Low-Carbon Commuting

# Identify high-emission commuters
high_emitters = []

for emp in response.get('items', []):
    co2e = emp.get('co2e', 0) or 0
    
    # Threshold: employees above average
    if co2e > (total_co2e / total_employees) * 1.5:
        high_emitters.append({
            "email": emp.get('email'),
            "transport": emp.get('transport_type'),
            "co2e": co2e,
            "distance": emp.get('total_km', 0),
        })

print(f"\n🎯 High-Emission Commuters ({len(high_emitters)}):")
for emitter in high_emitters[:10]:
    print(f"   {emitter['email']}")
    print(f"      Transport: {emitter['transport']} | Distance: {emitter['distance']} km")
    print(f"      COβ‚‚e: {emitter['co2e']:,.0f} kg/year")
    
    # Suggest alternatives
    if emitter['transport'] == 'car' and emitter['distance'] < 10:
        print(f"      πŸ’‘ Consider cycling or e-bike")
    elif emitter['transport'] == 'car' and emitter['distance'] < 30:
        print(f"      πŸ’‘ Consider public transit or carpooling")

3. Calculate Intensity Metrics

# Calculate emissions per employee per workday
def calculate_commuting_intensity():
    """Calculate kg COβ‚‚e per employee per workday"""
    
    total_co2e = 0
    total_workdays = 0
    
    for emp in response.get('items', []):
        co2e = emp.get('co2e', 0) or 0
        weekly_travels = emp.get('weekly_travels', [])
        
        total_co2e += co2e
        # Estimate workdays per year (52 weeks Γ— days per week)
        total_workdays += len(weekly_travels) * 52
    
    if total_workdays > 0:
        return total_co2e / total_workdays
    return 0

intensity = calculate_commuting_intensity()
print(f"\nπŸ“Š Commuting Intensity: {intensity:.2f} kg COβ‚‚e per workday")

# Benchmark
if intensity > 5:
    print("   ⚠️ High intensity - promote alternatives")
elif intensity > 2:
    print("   πŸ“ˆ Moderate - encourage public transit")
else:
    print("   βœ… Good - maintain sustainable commuting")
Reduction Strategies for Category 7
  1. Remote work policy: Allow 2+ days WFH per week
  2. Public transit subsidies: Incentivize train/bus use
  3. Cycle-to-work schemes: Provide bike facilities and subsidies
  4. Carpooling programs: Connect employees on similar routes
  5. Electric vehicle charging: Install workplace chargers
  6. Shuttle services: Provide company buses for major routes
  7. Flexible hours: Avoid peak traffic (lower congestion emissions)

Troubleshooting

Issue: Distance Not Calculated

# Provide distance directly if geocoding fails
employee = {
    "email": "[email protected]",
    "total_km": 15,  # Provide direct one-way distance
    "transport_type": "car",
    "weekly_travels": [0, 1, 2, 3, 4],
}

Issue: Zero Emissions for Non-Remote Worker

# Check common causes
def diagnose_zero_emissions(employee):
    """Diagnose why an employee has zero emissions"""
    
    issues = []
    
    # Check if fully remote
    if not employee.get('weekly_travels'):
        issues.append("weekly_travels is empty (remote worker)")
        return issues
    
    # Check if zero distance
    if not employee.get('total_km'):
        issues.append("total_km is missing or zero")
    
    # Check if zero-emission transport
    if employee.get('transport_type') in ['bicycle', 'walk']:
        issues.append(f"Zero-emission transport: {employee.get('transport_type')}")
    
    # Check if missing commuting period
    if not employee.get('employees_historic'):
        issues.append("No commuting period (employees_historic) created")
    
    return issues

for emp in response.get('items', []):
    if emp.get('co2e', 0) == 0:
        issues = diagnose_zero_emissions(emp)
        if issues:
            print(f"⚠️ {emp.get('email')}: {', '.join(issues)}")

Issue: Category 7 Seems Too Low

# Common reasons for underreported commuting emissions
checks = {
    "Missing employees": "Ensure all employees are in the system",
    "Remote misclassification": "Check remote workers aren't marked as office",
    "Missing transport details": "Ensure transport_type is specified",
    "Missing distance": "Provide total_km or origin/destination",
    "Missing periods": "Create employees_historic records",
    "Inactive employees": "Check enabled=True filter",
}

print("πŸ” Checklist for Category 7 completeness:")
for issue, action in checks.items():
    print(f"   ☐ {issue}")
    print(f"      β†’ {action}")

Next Steps