Office Cleaning Calculator

Help businesses understand their commercial cleaning costs with this detailed calculator. Supports various office types including standard offices, medical/dental facilities, coworking spaces, retail, and warehouses. Factor in square footage, number of rooms, cleaning frequency, service timing, and add-on services. Perfect for janitorial companies serving commercial clients with recurring cleaning contracts.

Home Services

Try the Calculator

Commercial Cleaning Quote
🏢 Facility Details
5000sq ft
5000 sq ft
50050000
 
 
📐 Space Layout
 
 
 
 
📅 Service Schedule
 
 
 
🧹 Standard Services
 
 
✨ Premium Add-Ons
 
 

💰 Your Quote
$ 515.00
$ -77.00

$ 438.00
$ 1,751.00
/mo
4 visits/month
Final pricing confirmed after walkthrough. Add-on services billed monthly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
export function officeCleaningCalculator(form: FormTs) {
// Base rates per sq ft by office type
const officeTypeRates: Record<string, number> = {
'standard': 0.08,
'medical': 0.15,
'dental': 0.14,
'coworking': 0.10,
'retail': 0.09,
'warehouse': 0.05,
'industrial': 0.06,
'restaurant': 0.12,
'gym': 0.11
};
 
// Frequency discounts
const frequencyDiscounts: Record<string, number> = {
'one-time': 0,
'daily': 30,
'3x-week': 25,
'2x-week': 20,
'weekly': 15,
'bi-weekly': 10,
'monthly': 5
};
 
// Time of day multipliers
const timeMultipliers: Record<string, number> = {
'daytime': 1.0,
'evening': 1.0,
'overnight': 1.15,
'weekend': 1.20
};
 
// Floor type rates (per sq ft for specialized care)
const floorTypeRates: Record<string, number> = {
'carpet': 0,
'hardwood': 0.02,
'tile': 0.01,
'concrete': 0,
'mixed': 0.01
};
 
// Helper functions
const getOfficeType = () => officeSection.dropdown('officeType')?.value() || 'standard';
const isMedicalOrDental = () => {
const type = getOfficeType();
return type === 'medical' || type === 'dental';
};
const isRestaurant = () => getOfficeType() === 'restaurant';
const isGym = () => getOfficeType() === 'gym';
const isWarehouseOrIndustrial = () => {
const type = getOfficeType();
return type === 'warehouse' || type === 'industrial';
};
 
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Commercial Cleaning Quote',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
 
form.addSpacer({ height: 20 });
 
// Office Details Section
const officeSection = form.addSubform('officeDetails', { title: '🏢 Facility Details' });
 
officeSection.addRow(row => {
row.addDropdown('officeType', {
label: 'Facility Type',
options: [
{ id: 'standard', name: 'Standard Office' },
{ id: 'medical', name: 'Medical Office / Clinic' },
{ id: 'dental', name: 'Dental Office' },
{ id: 'coworking', name: 'Coworking Space' },
{ id: 'retail', name: 'Retail / Showroom' },
{ id: 'restaurant', name: 'Restaurant / Café' },
{ id: 'gym', name: 'Gym / Fitness Center' },
{ id: 'warehouse', name: 'Warehouse / Storage' },
{ id: 'industrial', name: 'Light Industrial' }
],
defaultValue: 'standard',
isRequired: true
}, '1fr');
row.addSlider('squareFootage', {
label: 'Total Square Footage',
min: 500,
max: 50000,
step: 500,
defaultValue: 5000,
showValue: true,
unit: 'sq ft'
}, '1fr');
});
 
officeSection.addRow(row => {
row.addRadioButton('floorType', {
label: 'Primary Floor Type',
options: [
{ id: 'carpet', name: 'Carpet' },
{ id: 'hardwood', name: 'Hardwood' },
{ id: 'tile', name: 'Tile / Vinyl' },
{ id: 'concrete', name: 'Concrete' },
{ id: 'mixed', name: 'Mixed' }
],
defaultValue: 'carpet',
orientation: 'horizontal'
}, '1fr');
row.addInteger('floors', {
label: 'Number of Floors',
min: 1,
max: 10,
defaultValue: 1
}, '1fr');
});
 
// Standard office layout
const layoutSection = form.addSubform('layout', {
title: '📐 Space Layout',
isVisible: () => !isWarehouseOrIndustrial()
});
 
layoutSection.addRow(row => {
row.addInteger('privateOffices', {
label: 'Private Offices',
min: 0,
max: 50,
defaultValue: 5
}, '1fr');
row.addInteger('restrooms', {
label: 'Restrooms',
min: 1,
max: 20,
defaultValue: 2
}, '1fr');
});
 
layoutSection.addRow(row => {
row.addInteger('kitchenettes', {
label: 'Kitchens / Break Rooms',
min: 0,
max: 10,
defaultValue: 1
}, '1fr');
row.addInteger('conferenceRooms', {
label: 'Conference Rooms',
min: 0,
max: 20,
defaultValue: 2
}, '1fr');
});
 
// Restaurant specific
const restaurantSection = form.addSubform('restaurantDetails', {
title: '🍽️ Restaurant Details',
isVisible: isRestaurant
});
 
restaurantSection.addRow(row => {
row.addInteger('diningCapacity', {
label: 'Seating Capacity',
min: 10,
max: 500,
defaultValue: 50
}, '1fr');
row.addRadioButton('kitchenType', {
label: 'Kitchen Type',
options: [
{ id: 'small', name: 'Small / Prep Only' },
{ id: 'standard', name: 'Standard Commercial' },
{ id: 'large', name: 'Large / Full Service' }
],
defaultValue: 'standard',
orientation: 'horizontal'
}, '1fr');
});
 
restaurantSection.addRow(row => {
row.addCheckboxList('restaurantAreas', {
label: 'Areas to Clean',
options: [
{ id: 'dining', name: 'Dining Area' },
{ id: 'kitchen', name: 'Commercial Kitchen' },
{ id: 'bar', name: 'Bar Area' },
{ id: 'patio', name: 'Outdoor Patio' }
],
defaultValue: ['dining', 'kitchen']
});
});
 
// Gym specific
const gymSection = form.addSubform('gymDetails', {
title: '💪 Gym Details',
isVisible: isGym
});
 
gymSection.addRow(row => {
row.addCheckboxList('gymAreas', {
label: 'Areas to Clean',
options: [
{ id: 'weights', name: 'Weight Room / Floor' },
{ id: 'cardio', name: 'Cardio Area' },
{ id: 'locker', name: 'Locker Rooms' },
{ id: 'showers', name: 'Showers' },
{ id: 'pool', name: 'Pool Area' },
{ id: 'studio', name: 'Group Fitness Studios' }
],
defaultValue: ['weights', 'cardio', 'locker', 'showers']
}, '1fr');
row.addInteger('lockerRooms', {
label: 'Number of Locker Rooms',
min: 0,
max: 6,
defaultValue: 2
}, '1fr');
});
 
// Medical/Dental specific
const medicalSection = form.addSubform('medicalDetails', {
title: '🏥 Medical / Dental Details',
isVisible: isMedicalOrDental
});
 
medicalSection.addRow(row => {
row.addInteger('examRooms', {
label: 'Exam / Operatory Rooms',
min: 1,
max: 30,
defaultValue: 4
}, '1fr');
row.addInteger('waitingCapacity', {
label: 'Waiting Room Capacity',
min: 5,
max: 100,
defaultValue: 15
}, '1fr');
});
 
medicalSection.addRow(row => {
row.addCheckboxList('medicalServices', {
label: 'Specialized Services Needed',
options: [
{ id: 'biohazard', name: 'Biohazard Waste Handling (+$100/visit)' },
{ id: 'operatory', name: 'Operatory Deep Clean (+$25/room)' },
{ id: 'sterilization', name: 'Sterilization Area (+$50/visit)' },
{ id: 'hipaa', name: 'HIPAA-Compliant Shredding (+$30/visit)' }
],
defaultValue: []
});
});
 
// Service Schedule Section
const scheduleSection = form.addSubform('schedule', { title: '📅 Service Schedule' });
 
scheduleSection.addRow(row => {
row.addRadioButton('frequency', {
label: 'Cleaning Frequency',
options: [
{ id: 'daily', name: 'Daily (Mon-Fri) - 30% off' },
{ id: '3x-week', name: '3x per week - 25% off' },
{ id: '2x-week', name: '2x per week - 20% off' },
{ id: 'weekly', name: 'Weekly - 15% off' },
{ id: 'bi-weekly', name: 'Bi-weekly - 10% off' },
{ id: 'monthly', name: 'Monthly - 5% off' },
{ id: 'one-time', name: 'One-time deep clean' }
],
defaultValue: 'weekly',
orientation: 'vertical',
isRequired: true
});
});
 
scheduleSection.addRow(row => {
row.addRadioButton('serviceTime', {
label: 'Preferred Service Time',
options: [
{ id: 'daytime', name: 'Daytime (9am-5pm)' },
{ id: 'evening', name: 'Evening (5pm-10pm)' },
{ id: 'overnight', name: 'Overnight (10pm-6am) +15%' },
{ id: 'weekend', name: 'Weekend Only +20%' }
],
defaultValue: 'evening',
orientation: 'horizontal'
}, '1fr');
row.addDatepicker('startDate', {
label: 'Preferred Start Date',
minDate: new Date().toISOString().split('T')[0]
}, '1fr');
});
 
// Standard Services Section
const servicesSection = form.addSubform('services', { title: '🧹 Standard Services' });
 
servicesSection.addRow(row => {
row.addCheckboxList('standardServices', {
label: 'Included in Base Price',
options: [
{ id: 'vacuum', name: 'Vacuuming & Floor Cleaning' },
{ id: 'dust', name: 'Dusting All Surfaces' },
{ id: 'trash', name: 'Trash & Recycling Removal' },
{ id: 'restroom', name: 'Restroom Sanitization' },
{ id: 'kitchen', name: 'Kitchen / Break Room' },
{ id: 'glass', name: 'Interior Glass & Mirrors' }
],
defaultValue: ['vacuum', 'dust', 'trash', 'restroom', 'kitchen', 'glass'],
orientation: 'vertical'
}, '1fr');
row.addCheckboxList('additionalStandard', {
label: 'Add to Standard Service',
options: [
{ id: 'desks', name: 'Desk Surface Wipe-down' },
{ id: 'phones', name: 'Phone & Keyboard Sanitize' },
{ id: 'doors', name: 'Door Handle Disinfection' },
{ id: 'elevators', name: 'Elevator Cleaning' }
],
defaultValue: ['desks', 'doors'],
orientation: 'vertical'
}, '1fr');
});
 
// Add-on Services Section
const addonsSection = form.addSubform('addons', { title: '✨ Premium Add-Ons' });
 
addonsSection.addRow(row => {
row.addCheckboxList('floorAddons', {
label: 'Floor Care',
options: [
{ id: 'carpet', name: 'Carpet Deep Clean (+$0.15/sq ft)' },
{ id: 'wax', name: 'Hard Floor Waxing (+$0.20/sq ft)' },
{ id: 'strip', name: 'Floor Strip & Refinish (+$0.35/sq ft)' },
{ id: 'grout', name: 'Tile Grout Cleaning (+$0.10/sq ft)' }
],
defaultValue: []
}, '1fr');
row.addCheckboxList('surfaceAddons', {
label: 'Surfaces & Air',
options: [
{ id: 'windows', name: 'Exterior Windows (+$8/window)' },
{ id: 'highDust', name: 'High Dusting / Vents (+$0.03/sq ft)' },
{ id: 'sanitize', name: 'Enhanced Sanitization (+$0.05/sq ft)' },
{ id: 'air', name: 'Air Duct Cleaning (quote)' }
],
defaultValue: []
}, '1fr');
});
 
addonsSection.addRow(row => {
row.addInteger('windowCount', {
label: 'Number of Exterior Windows',
min: 0,
max: 500,
defaultValue: 20,
isVisible: () => {
const addons = addonsSection.checkboxList('surfaceAddons')?.value() || [];
return addons.includes('windows');
}
}, '1fr');
row.addCheckbox('supplies', {
label: 'Restroom Supplies Provided (+$50/restroom/month)',
defaultValue: false
}, '1fr');
});
 
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
 
// Price Calculation Helpers
const calculateBasePrice = () => {
const sqft = officeSection.slider('squareFootage')?.value() || 5000;
const officeType = getOfficeType();
const rate = officeTypeRates[officeType] || 0.08;
const floorType = officeSection.radioButton('floorType')?.value() || 'carpet';
const floorRate = floorTypeRates[floorType] || 0;
const floors = officeSection.integer('floors')?.value() || 1;
 
let basePrice = sqft * (rate + floorRate);
 
// Multi-floor surcharge
if (floors > 1) {
basePrice *= 1 + ((floors - 1) * 0.05);
}
 
// Add room-based pricing for standard offices
if (!isWarehouseOrIndustrial()) {
const privateOffices = layoutSection.integer('privateOffices')?.value() || 5;
const restrooms = layoutSection.integer('restrooms')?.value() || 2;
const kitchens = layoutSection.integer('kitchenettes')?.value() || 1;
const conference = layoutSection.integer('conferenceRooms')?.value() || 2;
basePrice += (privateOffices * 5) + (restrooms * 25) + (kitchens * 20) + (conference * 10);
}
 
// Restaurant specifics
if (isRestaurant()) {
const kitchenType = restaurantSection.radioButton('kitchenType')?.value() || 'standard';
const kitchenMultipliers: Record<string, number> = { 'small': 1.0, 'standard': 1.15, 'large': 1.30 };
basePrice *= kitchenMultipliers[kitchenType] || 1;
 
const areas = restaurantSection.checkboxList('restaurantAreas')?.value() || [];
if (areas.includes('bar')) basePrice += 75;
if (areas.includes('patio')) basePrice += 50;
}
 
// Gym specifics
if (isGym()) {
const areas = gymSection.checkboxList('gymAreas')?.value() || [];
const lockerRooms = gymSection.integer('lockerRooms')?.value() || 2;
if (areas.includes('showers')) basePrice += lockerRooms * 40;
if (areas.includes('pool')) basePrice += 150;
if (areas.includes('studio')) basePrice += 50;
}
 
// Medical specifics
if (isMedicalOrDental()) {
const examRooms = medicalSection.integer('examRooms')?.value() || 4;
basePrice += examRooms * 15;
}
 
return basePrice;
};
 
const calculateAddons = () => {
let total = 0;
const sqft = officeSection.slider('squareFootage')?.value() || 5000;
const restrooms = layoutSection.integer('restrooms')?.value() || 2;
 
const floorAddons = addonsSection.checkboxList('floorAddons')?.value() || [];
if (floorAddons.includes('carpet')) total += sqft * 0.15;
if (floorAddons.includes('wax')) total += sqft * 0.20;
if (floorAddons.includes('strip')) total += sqft * 0.35;
if (floorAddons.includes('grout')) total += sqft * 0.10;
 
const surfaceAddons = addonsSection.checkboxList('surfaceAddons')?.value() || [];
if (surfaceAddons.includes('windows')) {
const windows = addonsSection.integer('windowCount')?.value() || 20;
total += windows * 8;
}
if (surfaceAddons.includes('highDust')) total += sqft * 0.03;
if (surfaceAddons.includes('sanitize')) total += sqft * 0.05;
 
if (addonsSection.checkbox('supplies')?.value()) {
total += restrooms * 50;
}
 
// Medical add-ons
if (isMedicalOrDental()) {
const medServices = medicalSection.checkboxList('medicalServices')?.value() || [];
if (medServices.includes('biohazard')) total += 100;
if (medServices.includes('operatory')) {
const rooms = medicalSection.integer('examRooms')?.value() || 4;
total += rooms * 25;
}
if (medServices.includes('sterilization')) total += 50;
if (medServices.includes('hipaa')) total += 30;
}
 
return total;
};
 
const getVisitsPerMonth = () => {
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const visits: Record<string, number> = {
'daily': 22, '3x-week': 13, '2x-week': 9, 'weekly': 4,
'bi-weekly': 2, 'monthly': 1, 'one-time': 1
};
return visits[frequency] || 4;
};
 
// Price Summary Section
const summarySection = form.addSubform('summary', { title: '💰 Your Quote' });
 
summarySection.addRow(row => {
row.addPriceDisplay('basePrice', {
label: 'Base Cleaning (per visit)',
computedValue: () => Math.round(calculateBasePrice()),
variant: 'default'
}, '1fr');
row.addPriceDisplay('timeAdjustment', {
label: 'Time Premium',
computedValue: () => {
const base = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
const multiplier = timeMultipliers[time] || 1;
return Math.round(base * (multiplier - 1));
},
variant: 'default',
prefix: '+',
isVisible: () => {
const time = scheduleSection.radioButton('serviceTime')?.value();
return time === 'overnight' || time === 'weekend';
}
}, '1fr');
});
 
summarySection.addRow(row => {
row.addPriceDisplay('addonsPrice', {
label: 'Premium Add-Ons',
computedValue: () => Math.round(calculateAddons()),
variant: 'default',
prefix: '+',
isVisible: () => calculateAddons() > 0
}, '1fr');
row.addPriceDisplay('frequencyDiscount', {
label: 'Frequency Discount',
computedValue: () => {
const base = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
const timeMult = timeMultipliers[time] || 1;
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const discountPercent = frequencyDiscounts[frequency] || 0;
return -Math.round(base * timeMult * discountPercent / 100);
},
variant: 'success',
isVisible: () => {
const frequency = scheduleSection.radioButton('frequency')?.value();
return frequency !== 'one-time';
}
}, '1fr');
});
 
summarySection.addSpacer({ showLine: true, lineStyle: 'solid', lineColor: '#e2e8f0' });
 
summarySection.addRow(row => {
row.addPriceDisplay('perVisitPrice', {
label: 'Price Per Visit',
computedValue: () => {
let total = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
total *= timeMultipliers[time] || 1;
 
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const discountPercent = frequencyDiscounts[frequency] || 0;
total *= (1 - discountPercent / 100);
 
return Math.round(total);
},
variant: 'highlight'
}, '1fr');
row.addPriceDisplay('monthlyEstimate', {
label: 'Monthly Estimate',
computedValue: () => {
let perVisit = calculateBasePrice();
const time = scheduleSection.radioButton('serviceTime')?.value() || 'evening';
perVisit *= timeMultipliers[time] || 1;
 
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const discountPercent = frequencyDiscounts[frequency] || 0;
perVisit *= (1 - discountPercent / 100);
 
const visits = getVisitsPerMonth();
const addons = calculateAddons();
 
return Math.round((perVisit * visits) + addons);
},
variant: 'large',
suffix: '/mo'
}, '1fr');
});
 
summarySection.addRow(row => {
row.addTextPanel('visitInfo', {
computedValue: () => {
const frequency = scheduleSection.radioButton('frequency')?.value() || 'weekly';
const info: Record<string, string> = {
'daily': '22 visits/month (Mon-Fri)',
'3x-week': '13 visits/month',
'2x-week': '9 visits/month',
'weekly': '4 visits/month',
'bi-weekly': '2 visits/month',
'monthly': '1 visit/month',
'one-time': 'Single deep clean visit'
};
return info[frequency] || '';
},
customStyles: { 'font-size': '0.9rem', 'color': '#059669', 'text-align': 'center' }
});
});
 
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'Final pricing confirmed after walkthrough. Add-on services billed monthly.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'font-style': 'italic', 'text-align': 'center' }
});
});
 
form.configureSubmitButton({
label: 'Request Free Walkthrough'
});
}
 

Frequently Asked Questions

Can I set different rates for different office types?

Yes. The calculator includes separate rates for standard offices, medical/dental offices, coworking spaces, retail, warehouse, and industrial spaces. Each can be customized to reflect your actual pricing structure.

How do frequency discounts work?

The calculator automatically applies discounts for recurring services - from 5% for monthly service up to 30% for daily cleaning. You can adjust these percentages to match your actual discount structure.

Can I handle medical and dental office requirements?

Yes. When medical or dental office type is selected, additional options appear for biohazard handling, operatory/exam room deep cleaning, and other healthcare-specific services with appropriate pricing.

Does this calculate monthly contract pricing?

Yes. The calculator shows both per-visit pricing and estimated monthly costs based on the selected frequency. This helps businesses understand their ongoing investment.

Can I add overnight or weekend service premiums?

Yes. The calculator includes service time options with customizable premiums for overnight cleaning (default +15%) and weekend service (default +20%).