DEV Community

Scott Coristine
Scott Coristine

Posted on • Originally published at signaturecare.ca

In-House Caregiver vs. Agency: A Technical Decision Framework for Montreal Families

Tags: caregiving montreal healthcare decisionmaking


When Montreal families face the challenge of arranging home care for a loved one, they're essentially solving a resource allocation and risk management problem — one that has measurable variables, hidden costs, and compliance requirements that can be modeled and compared systematically.

This guide breaks down the decision using a technical lens: cost modeling, compliance overhead, risk scoring, and operational tradeoffs. Whether you're a developer building a care-coordination tool, or simply someone who thinks in systems, this framework will help you or your family make a well-informed choice.

Full guide available at signaturecare.ca if you want the non-technical version for other family members.


Modeling the Two Options

Think of home care as a service delivery system with two distinct architectural patterns:

Option A: Private Caregiver (Self-Managed)
┌─────────────────────────────────────────────┐
│              Family (Employer)              │
│  ┌─────────┐   ┌──────────┐   ┌──────────┐ │
│  │ Payroll │   │ Compliance│  │ Backup   │ │
│  │ Mgmt    │   │ (CNESST, │   │ Coverage │ │
│  │         │   │ QPP, EI) │   │ (Manual) │ │
│  └─────────┘   └──────────┘   └──────────┘ │
│                    │                        │
│           ┌────────▼────────┐               │
│           │  Single Point   │               │
│           │  of Failure:    │               │
│           │  Private        │               │
│           │  Caregiver      │               │
│           └─────────────────┘               │
└─────────────────────────────────────────────┘

Option B: Agency Model (Managed Service)
┌─────────────────────────────────────────────┐
│               Home Care Agency              │
│  ┌─────────┐   ┌──────────┐   ┌──────────┐ │
│  │ HR +    │   │ Legal +  │   │ Caregiver│ │
│  │ Payroll │   │ Insurance│   │ Pool     │ │
│  └─────────┘   └──────────┘   └──────────┘ │
│                    │                        │
│         ┌──────────▼──────────┐             │
│         │  Redundant Caregiver│             │
│         │  Assignment with    │             │
│         │  Failover Coverage  │             │
│         └─────────────────────┘             │
│                    │                        │
│           ┌────────▼────────┐               │
│           │     Family      │               │
│           └─────────────────┘               │
└─────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The private model gives you direct control but zero redundancy. The agency model abstracts away complexity at the cost of some control — essentially the classic build vs. buy tradeoff in software engineering.


True Cost Calculation

Surface-level hourly rates are misleading. Here's how to calculate Total Cost of Ownership (TCO) for each model:

Private Caregiver TCO

def calculate_private_caregiver_tco(
    hourly_rate: float,
    hours_per_week: float,
    weeks_per_year: int = 52
) -> dict:
    """
    Calculate true annual cost of a private caregiver in Quebec.

    Quebec employer contributions (2024 approximate rates):
    - QPP (Quebec Pension Plan):     5.40% of insurable earnings
    - EI  (Employment Insurance):    2.28% of insurable earnings
    - CNESST (workplace safety):     ~1.50% depending on industry
    - RQAP (parental insurance):     0.692% of insurable earnings
    """

    base_annual_cost = hourly_rate * hours_per_week * weeks_per_year

    # Mandatory employer contributions
    qpp_contribution         = base_annual_cost * 0.054
    ei_contribution          = base_annual_cost * 0.0228
    cnesst_contribution      = base_annual_cost * 0.015
    rqap_contribution        = base_annual_cost * 0.00692

    # Hidden operational costs (conservative estimates)
    liability_insurance      = 800      # Annual policy, CAD
    admin_hours_per_week     = 2        # Payroll, scheduling, compliance
    admin_cost_per_hour      = 25       # Opportunity cost of family time
    annual_admin_cost        = admin_hours_per_week * admin_cost_per_hour * 52

    # Backup coverage cost (average 8-12 absences/year)
    avg_absences_per_year    = 10
    avg_absence_duration_hrs = 8
    backup_hourly_rate       = hourly_rate * 1.3  # Rushed replacement premium
    backup_coverage_cost     = avg_absences_per_year * avg_absence_duration_hrs * backup_hourly_rate

    total_tco = (
        base_annual_cost
        + qpp_contribution
        + ei_contribution
        + cnesst_contribution
        + rqap_contribution
        + liability_insurance
        + annual_admin_cost
        + backup_coverage_cost
    )

    effective_hourly_rate = total_tco / (hours_per_week * weeks_per_year)

    return {
        "base_annual_cost":        round(base_annual_cost, 2),
        "employer_contributions":  round(qpp_contribution + ei_contribution + cnesst_contribution + rqap_contribution, 2),
        "liability_insurance":     liability_insurance,
        "annual_admin_cost":       annual_admin_cost,
        "backup_coverage_cost":    round(backup_coverage_cost, 2),
        "total_tco":               round(total_tco, 2),
        "effective_hourly_rate":   round(effective_hourly_rate, 2)
    }


# Example: $20/hr caregiver, 20 hours/week
result = calculate_private_caregiver_tco(20.0, 20)
print(result)
Enter fullscreen mode Exit fullscreen mode

Sample output:

{
  "base_annual_cost":        20800.00,
  "employer_contributions":   2839.42,
  "liability_insurance":       800.00,
  "annual_admin_cost":        2600.00,
  "backup_coverage_cost":     2080.00,
  "total_tco":               29119.42,
  "effective_hourly_rate":    27.99
}
Enter fullscreen mode Exit fullscreen mode

That $20/hr caregiver is actually costing you closer to $28/hr in real terms — a ~40% hidden cost overhead.

Agency Model TCO

def calculate_agency_tco(
    agency_hourly_rate: float,
    hours_per_week: float,
    weeks_per_year: int = 52
) -> dict:
    """
    Agency rates are all-inclusive. The overhead calculation is simpler
    because employment obligations are fully abstracted away.

    Typical Montreal agency rates: $28-38/hr (all-in)
    """

    base_annual_cost   = agency_hourly_rate * hours_per_week * weeks_per_year
    admin_overhead     = 0      # Handled by agency
    backup_coverage    = 0      # Included in service agreement
    liability          = 0      # Covered by agency insurance

    # Only additional cost: care plan assessments (typically 1-2/year)
    annual_assessments = 200    # CAD, approximate

    total_tco = base_annual_cost + annual_assessments

    return {
        "base_annual_cost":  round(base_annual_cost, 2),
        "hidden_costs":      0,
        "annual_assessments": annual_assessments,
        "total_tco":         round(total_tco, 2),
        "effective_hourly_rate": round(total_tco / (hours_per_week * weeks_per_year), 2)
    }


result = calculate_agency_tco(30.0, 20)
print(result)
Enter fullscreen mode Exit fullscreen mode

Sample output:

{
  "base_annual_cost":     31200.00,
  "hidden_costs":             0,
  "annual_assessments":     200.00,
  "total_tco":            31400.00,
  "effective_hourly_rate":  30.19
}
Enter fullscreen mode Exit fullscreen mode

Side-by-Side Comparison

TCO Comparison (20 hrs/week, full year):
─────────────────────────────────────────────────────
                     Private ($20/hr)  Agency ($30/hr)
─────────────────────────────────────────────────────
Base cost               $20,800         $31,200
Employer contributions   $2,839              $0
Insurance                  $800              $0
Admin overhead           $2,600              $0
Backup coverage          $2,080              $0
Assessments                  $0            $200
─────────────────────────────────────────────────────
TOTAL TCO               $29,119         $31,400
Effective $/hr            $27.99          $30.19
─────────────────────────────────────────────────────
Actual difference:        +$2,281/year  (+7.8%)
─────────────────────────────────────────────────────
Enter fullscreen mode Exit fullscreen mode

The real cost gap is much smaller than the advertised hourly rate gap suggests — and this doesn't yet account for the compliance risk exposure.


Risk Scoring Matrix

Every system has failure modes. Here's a structured risk assessment:

from dataclasses import dataclass
from typing import List

@dataclass
class RiskFactor:
    name: str
    private_score: int    # 1 (low risk) to 5 (high risk)
    agency_score: int
    weight: float         # Relative importance 0.0-1.0
    notes: str

risk_factors: List[RiskFactor] = [
    RiskFactor(
        name="Regulatory Compliance (CNESST, QPP, EI)",
        private_score=5,
        agency_score=1,
        weight=0.25,
        notes="Family assumes full Quebec labour law liability"
    ),
    RiskFactor(
        name="Caregiver Availability / Continuity",
        private_score=4,
        agency_score=2,
        weight=0.20,
        notes="Single point of failure vs. caregiver pool"
    ),
    RiskFactor(
        name="Credential Verification",
        private_score=4,
        agency_score=1,
        weight=0.20,
        notes="Unverified self-reporting vs. systematic screening"
    ),
    RiskFactor(
        name="Quality Assurance",
        private_score=3,
        agency_score=2,
        weight=0.15,
        notes="Family must self-monitor vs. supervisor check-ins"
    ),
    RiskFactor(
        name="Cost Predictability",
        private_score=3,
        agency_score=1,
        weight=0.10,
        notes="Variable hidden costs vs. fixed all-in rates"
    ),
    RiskFactor(
        name="Control & Flexibility",
        private_score=1,
        agency_score=3,
        weight=0.10,
        notes="Private offers more direct scheduling control"
    ),
]

def calculate_weighted_risk(factors: List[RiskFactor]) -> dict:
    private_risk = sum(f.private_score * f.weight for f in factors)
    agency_risk  = sum(f.agency_score  * f.weight for f in factors)

    return {
        "private_weighted_risk": round(private_risk, 2),
        "agency_weighted_risk":  round(agency_risk, 2),
        "risk_reduction":        round(((private_risk - agency_risk) / private_risk) * 100, 1)
    }

scores = calculate_weighted_risk(risk_factors)
print(scores)
# Output:
# { 'private_weighted_risk': 3.65, 'agency_weighted_risk': 1.60, 'risk_reduction': 56.2 }
Enter fullscreen mode Exit fullscreen mode

The agency model reduces weighted operational risk by approximately 56% in this scoring model — consistent with published data showing professional screening reduces care-related incidents by up to 60%.


Quebec Compliance Checklist

If you proceed with the private model, here's a compliance checklist you should treat as non-negotiable:

## Quebec Private Employer Compliance Checklist

### Registration & Setup
- [ ] Register as an employer with Revenu Québec (TP-1015.3-V)
- [ ] Register with Service Canada for payroll deductions
- [ ] Register with CNESST for workplace safety coverage
- [ ] Obtain employer liability insurance policy

### Each Pay Period
- [ ] Deduct and remit federal/provincial income tax
- [ ] Deduct and remit QPP contributions (employee + employer share)
- [ ] Deduct and remit EI premiums (employee + employer share)
- [ ] Deduct and remit RQAP contributions
- [ ] Maintain accurate timesheet records

### Annual Requirements
- [ ] Issue T4 and Relevé 1 slips by end of February
- [ ] File employer summary with CRA and Revenu Québec
- [ ] Renew CNESST registration and update payroll declaration
- [ ] Review and update liability insurance coverage

### Documentation
- [ ] Signed employment contract (bilingual recommended)
- [ ] Copy of caregiver certifications and credentials
- [ ] Background check results on file
- [ ] Emergency contact and protocol documentation
Enter fullscreen mode Exit fullscreen mode

Missing any of these can result in significant financial penalties — retroactive premiums, interest charges, and in some cases personal liability. Agencies like Signature Care absorb this entire compliance stack on your behalf.


Decision Algorithm

Here's a structured decision tree to guide your choice:


python
def recommend_care_model(
    has_admin_capacity: bool,
    care_complexity: str,        # "low" | "medium" | "high"
    needs_bilingual: bool,
    budget_flexible: bool,
    hours_per_week: float
) -> str:
    """
    Simple decision support algorithm for Montreal home care selection.
    care_complexity: "low" = companionship/errands
                     "medium" = personal care, medication reminders
                     "high" = dementia, post-surgical, medical needs
    """

    # High-complexity care should almost always go through an agency
    if care_complexity == "high":
        return (
            "RECOMMEND: Agency\n"
            "Reason: High-complexity medical or cognitive care requires "
            "professionally trained and supervised caregivers, plus "
            "coordinated backup coverage."
        )

    # Heavy hours increase compliance and backup risks
    if hours_per_week >= 30:
        return (
            "RECOMMEND: Agency\n"
            "Reason: High weekly hours significantly increase employer "
            "compliance burden and backup coverage risk."
        )

    # Bilingual/multicultural matching is much easier through agencies
    if needs_bilingual and not has_admin_capacity:
        return (
            "RECOMMEND: Agency\n"
            "Reason: Bilingual caregiver matching combined with limited "
            "admin capacity points strongly to agency model."
Enter fullscreen mode Exit fullscreen mode

Top comments (0)