Commercial general liability

A class and exposure rated CGL model with increased limit factors and a claims load.

A default model in Ptally. Commercial General Liability: Class + Exposure Rated is one of the default models you can select when you start a new project in Ptally. It comes with its rate tables, rules and 6 tests, ready to adapt to your own product.
The line of business

Commercial general liability

Commercial general liability (CGL) covers a business against third-party bodily injury and property damage claims. Premium depends on what the business does, how much of it it does, where it operates and the limit of cover.

Methodology

How the model rates

Each class code has a rate per $1,000 of exposure, such as payroll or sales. The exposure-based premium is adjusted by a state factor, an increased limit factor (1.00 at a $1m occurrence limit) and a load for prior claims.

A policy fee and a minimum premium are applied. Exposures outside the middle market are declined, and high-hazard classes, claim-heavy accounts and $5m limits are referred.

Three further factors adjust the premium: how long the business has traded, the share of work subcontracted and any products and completed operations exposure.

8inputs
11steps
6lookup tables
6tests

Inputs

8 fields
FieldLabelTypeDefaultAllowed values
class_codeGL class codestringofficesoffices, retail, contractors_light, contractors_roofing, restaurants, light_manufacturing
stateStatestringCACA, NY, TX, FL, IL
exposureExposure ($)integer500000100000, 500000, 2000000, 10000000
occurrence_limitPer-occurrence limit ($)integer1000000500000, 1000000, 2000000, 5000000
prior_claims_3yPrior GL claims in last 3 yearsinteger00, 1, 3, 5
years_in_businessYears in businessinteger51, 3, 5, 10
subcontracted_pctWork subcontracted (%)integer00, 25, 50, 75
products_completed_opsProducts and completed operationsbooleanfalsefalse, true
The model

Step by step

Steps run in order. Each one can use the inputs and the outputs of every step before it.

01Lookup table
GL class base rate

Rate per $1000 exposure and exposure basis by class code. Roofing and restaurants carry the highest loads.

{
  "id": "class_gl_rates",
  "key": "class_gl_rates",
  "step": "collection",
  "name": "GL class base rate",
  "retain": true,
  "collection": [
    ["class_code", "gl_rate_per_k", "exposure_basis", "high_hazard"],
    ["offices", 1.1, "payroll", false],
    ["retail", 2.2, "sales", false],
    ["contractors_light", 6.5, "payroll", false],
    ["contractors_roofing", 22, "payroll", true],
    ["restaurants", 8.4, "sales", false],
    ["light_manufacturing", 4.8, "payroll", false]
  ],
  "format": {
    "gl_rate_per_k": {
      "key": "gl_rate_per_k",
      "label": "GL rate per $1000 exposure",
      "exp": "collection.filter(class_code=={{class_code}}).map(gl_rate_per_k).first()",
      "type": "decimal",
      "def": 2
    },
    "class_exposure_basis": {
      "key": "class_exposure_basis",
      "label": "Exposure basis",
      "exp": "collection.filter(class_code=={{class_code}}).map(exposure_basis).first()",
      "type": "string",
      "def": "payroll"
    },
    "class_high_hazard": {
      "key": "class_high_hazard",
      "label": "High-hazard class flag",
      "exp": "collection.filter(class_code=={{class_code}}).map(high_hazard).first()",
      "type": "boolean",
      "def": false
    }
  }
}
02Lookup table
State GL factor

State load: plaintiff-friendly and coastal states run higher.

{
  "id": "state_gl_rates",
  "key": "state_gl_rates",
  "step": "collection",
  "name": "State GL factor",
  "retain": true,
  "collection": [
    ["state", "state_gl_factor"],
    ["CA", 1.15],
    ["NY", 1.25],
    ["TX", 1],
    ["FL", 1.2],
    ["IL", 1.05]
  ],
  "format": {
    "state_gl_factor": {
      "key": "state_gl_factor",
      "label": "State GL factor",
      "exp": "collection.filter(state=={{state}}).map(state_gl_factor).first()",
      "type": "decimal",
      "def": 1
    }
  }
}
03Lookup table
Increased limits factor

Standard ILF curve: factor 1.00 at $1m occurrence limit, escalating to $5m.

{
  "id": "limit_rates",
  "key": "limit_rates",
  "step": "collection",
  "name": "Increased limits factor",
  "retain": true,
  "collection": [
    ["limit_max", "limit_factor"],
    [500000, 0.8],
    [1000000, 1],
    [2000000, 1.35],
    [5000000, 1.85]
  ],
  "format": {
    "limit_factor": {
      "key": "limit_factor",
      "label": "Increased limits factor",
      "exp": "collection.filter(limit_max>={{occurrence_limit}}).map(limit_factor).first()",
      "type": "decimal",
      "def": 1
    }
  }
}
04Calculation
Claims history load

Each prior claim in the last 3 years adds 10%, capped at 60%.

{
  "id": "claims_load_calc",
  "key": "claims_load_calc",
  "step": "calculation",
  "name": "Claims history load",
  "def": 1,
  "formula": "min(1 + ({{prior_claims_3y}} * 0.10), 1.60)"
}
05Lookup table
Years in business factor

Established businesses tend to have better processes and fewer claims than new ones.

{
  "id": "gl_experience_rates",
  "key": "gl_experience_rates",
  "step": "collection",
  "name": "Years in business factor",
  "retain": true,
  "collection": [
    ["years_in_business_min", "years_in_business_max", "gl_experience_factor_rel"],
    [0, 2, 1.15],
    [3, 4, 1.05],
    [5, 9, 1],
    [10, 999, 0.95]
  ],
  "format": {
    "gl_experience_factor": {
      "key": "gl_experience_factor",
      "label": "Years in business factor",
      "exp": "collection.filter(years_in_business_min<={{years_in_business}}).filter(years_in_business_max>={{years_in_business}}).map(gl_experience_factor_rel).first()",
      "type": "decimal",
      "def": 1
    }
  }
}
06Lookup table
Subcontracted work factor

Work done by subcontractors is harder to control and can bring their liability back to the insured.

{
  "id": "subcontract_rates",
  "key": "subcontract_rates",
  "step": "collection",
  "name": "Subcontracted work factor",
  "retain": true,
  "collection": [
    ["subcontracted_pct_min", "subcontracted_pct_max", "subcontract_factor_rel"],
    [0, 10, 1],
    [11, 40, 1.08],
    [41, 100, 1.18]
  ],
  "format": {
    "subcontract_factor": {
      "key": "subcontract_factor",
      "label": "Subcontracted work factor",
      "exp": "collection.filter(subcontracted_pct_min<={{subcontracted_pct}}).filter(subcontracted_pct_max>={{subcontracted_pct}}).map(subcontract_factor_rel).first()",
      "type": "decimal",
      "def": 1
    }
  }
}
07Lookup table
Products and completed operations factor

Liability for products sold or work already finished adds exposure after the job is done.

{
  "id": "products_rates",
  "key": "products_rates",
  "step": "collection",
  "name": "Products and completed operations factor",
  "retain": true,
  "collection": [
    ["products_completed_ops_value", "products_factor_rel"],
    [false, 1],
    [true, 1.15]
  ],
  "format": {
    "products_factor": {
      "key": "products_factor",
      "label": "Products and completed operations factor",
      "exp": "collection.filter(products_completed_ops_value=={{products_completed_ops}}).map(products_factor_rel).first()",
      "type": "decimal",
      "def": 1
    }
  }
}
08Calculation
Base premium

Exposure in thousands × class rate × state × limit × claims load. Multiplied by the years in business factor, subcontracted work factor, products and completed operations factor.

{
  "id": "base_premium",
  "key": "base_premium",
  "step": "calculation",
  "name": "Base premium",
  "def": 0,
  "formula": "round(({{exposure}} / 1000) * {{gl_rate_per_k}} * {{state_gl_factor}} * {{limit_factor}} * {{claims_load_calc}} * {{gl_experience_factor}} * {{subcontract_factor}} * {{products_factor}}, 2)"
}
09Calculation
Policy premium

Add $150 policy fee. Minimum premium is $500.

{
  "id": "policy_premium",
  "key": "policy_premium",
  "step": "calculation",
  "name": "Policy premium",
  "def": 0,
  "formula": "round(max({{base_premium}} + 150, 500), 2)"
}
10Decline rules
General liability exclusions

Decline exposures under $10k or over $50m (outside standard middle-market GL).

{
  "id": "gl_exclusions",
  "key": "gl_exclusions",
  "step": "exclusion",
  "name": "General liability exclusions",
  "def": false,
  "items": [
    {
      "id": "exposure_too_low",
      "name": "Exposure below $10k",
      "exp": "{{exposure}} < 10000",
      "def": false
    },
    {
      "id": "exposure_too_high",
      "name": "Exposure over $50m",
      "exp": "{{exposure}} > 50000000",
      "def": false
    }
  ]
}
11Refer rules
General liability refers

Refer high-hazard classes (roofing), claim-heavy accounts, and $5m limits for underwriter review.

{
  "id": "gl_refers",
  "key": "gl_refers",
  "step": "refer",
  "name": "General liability refers",
  "def": false,
  "items": [
    {
      "id": "high_hazard_class",
      "name": "High-hazard class code",
      "exp": "{{class_high_hazard}} == true",
      "def": false
    },
    {
      "id": "claims_heavy",
      "name": "3+ prior claims",
      "exp": "{{prior_claims_3y}} >= 3",
      "def": false
    },
    {
      "id": "max_limit",
      "name": "$5m occurrence limit",
      "exp": "{{occurrence_limit}} >= 5000000",
      "def": false
    }
  ]
}
Worked example

Worked example: established firm subcontracting a quarter of its work

This quote was priced by the Ptally rating engine. The trace below follows it through every step to the final result.

Quote input
{
  "class_code": "offices",
  "state": "CA",
  "exposure": 400000,
  "occurrence_limit": 1000000,
  "prior_claims_3y": 0,
  "years_in_business": 12,
  "subcontracted_pct": 25,
  "products_completed_ops": true
}
Result747.03VALID
Calculation trace
  1. GL class base rateLookup table
    gl_rate_per_k = 1.1 · class_exposure_basis = "payroll" · class_high_hazard = false
  2. State GL factorLookup table
    state_gl_factor = 1.15
  3. Increased limits factorLookup table
    limit_factor = 1
  4. Claims history loadCalculation
    min(1 + (0 * 0.10), 1.60) = 1
  5. Years in business factorLookup table
    gl_experience_factor = 0.95
  6. Subcontracted work factorLookup table
    subcontract_factor = 1.08
  7. Products and completed operations factorLookup table
    products_factor = 1.15
  8. Base premiumCalculation
    round((400,000 / 1000) * 1.1 * 1.15 * 1 * 1 * 0.95 * 1.08 * 1.15, 2) = 597.03
  9. Policy premiumCalculation
    round(max(597.03 + 150, 500), 2) = 747.03
  10. General liability exclusionsDecline rules
    Exposure below $10k: not firedExposure over $50m: not fired
  11. General liability refersRefer rules
    High-hazard class code: not fired3+ prior claims: not fired$5m occurrence limit: not fired
Start from this model

Select commercial general liability as the default model for a new project, then change the rates, rules and tests to match your product. Our consultants can do this for you, with no implementation fee.

Talk to our team