Cleaning Service Feedback Form

Quality is everything in the cleaning industry. This feedback form helps cleaning companies understand client satisfaction across multiple dimensions: thoroughness of cleaning, staff professionalism, punctuality, and value for money. The form includes room-by-room ratings, specific area assessments, and captures both one-time and recurring service feedback. Perfect for residential cleaning, commercial janitorial services, and specialized cleaning businesses.

Specialized

Try the Form

Your feedback helps us maintain the highest standards.
Service Details
 
 
Overall Satisfaction
0/5
Room-by-Room Quality
 
Thoroughness
Cleaning Team
0/5
Value for Money
7
7
110
๐Ÿ˜Š Good value - Worth the price
Recommendation
Not at all likely
Extremely likely
Additional Comments
Feedback Summary
๐Ÿงน Cleaning Service Feedback โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โญ Overall: (0/5) ๐Ÿ‘ฅ Team: (0/5) ๐Ÿ’ฐ Value: 7/10
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
export function cleaningServiceFeedback(form: FormTs) {
// Cleaning Service Feedback Form
// Demonstrates: RatingScale (NPS), StarRating, MatrixQuestion, EmojiRating, RadioButton, CheckboxList, Slider, SuggestionChips, ThumbRating
 
// ============================================
// HEADER
// ============================================
form.addRow(row => {
row.addTextPanel('header', {
label: 'How Was Your Cleaning?',
computedValue: () => 'Your feedback helps us maintain the highest standards.',
customStyles: {
backgroundColor: '#22c55e',
color: 'white',
padding: '24px',
borderRadius: '12px',
textAlign: 'center'
}
});
});
 
// ============================================
// SECTION 1: Service Details
// ============================================
const serviceSection = form.addSubform('service', {
title: 'Service Details'
});
 
serviceSection.addRow(row => {
row.addRadioButton('serviceType', {
label: 'What type of cleaning was performed?',
options: [
{ id: 'regular', name: 'Regular/Recurring Clean' },
{ id: 'deep', name: 'Deep Clean' },
{ id: 'move', name: 'Move In/Out Clean' },
{ id: 'onetime', name: 'One-Time Service' },
{ id: 'office', name: 'Office/Commercial Clean' }
],
orientation: 'vertical',
isRequired: true
}, '1fr');
row.addRadioButton('frequency', {
label: 'How often do you use our service?',
options: [
{ id: 'first', name: 'First time' },
{ id: 'weekly', name: 'Weekly' },
{ id: 'biweekly', name: 'Every 2 weeks' },
{ id: 'monthly', name: 'Monthly' },
{ id: 'occasional', name: 'Occasional' }
],
orientation: 'vertical'
}, '1fr');
});
 
// ============================================
// SECTION 2: Overall Satisfaction
// ============================================
const satisfactionSection = form.addSubform('satisfaction', {
title: 'Overall Satisfaction',
customStyles: { backgroundColor: '#f0fdf4', padding: '16px', borderRadius: '8px' }
});
 
satisfactionSection.addRow(row => {
row.addStarRating('overallRating', {
label: 'How would you rate this cleaning overall?',
maxStars: 5,
size: 'xl',
showCounter: true,
alignment: 'center',
showConfettiOnMax: true
});
});
 
satisfactionSection.addSpacer({ height: '16px' });
 
satisfactionSection.addRow(row => {
row.addEmojiRating('satisfaction', {
label: 'How do you feel about the cleanliness of your space now?',
preset: 'satisfaction',
size: 'lg',
showLabels: true,
alignment: 'center'
});
});
 
// ============================================
// SECTION 3: Room-by-Room Ratings
// ============================================
const roomsSection = form.addSubform('rooms', {
title: 'Room-by-Room Quality',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
roomsSection.addRow(row => {
row.addCheckboxList('roomsCleaned', {
label: 'Which rooms were cleaned? (select all)',
options: [
{ id: 'kitchen', name: 'Kitchen' },
{ id: 'bathrooms', name: 'Bathroom(s)' },
{ id: 'living', name: 'Living Room' },
{ id: 'bedrooms', name: 'Bedroom(s)' },
{ id: 'dining', name: 'Dining Room' },
{ id: 'office', name: 'Home Office' },
{ id: 'laundry', name: 'Laundry Room' },
{ id: 'common', name: 'Common Areas' }
],
orientation: 'horizontal'
});
});
 
roomsSection.addSpacer({ height: '16px' });
 
roomsSection.addRow(row => {
row.addMatrixQuestion('roomRatings', {
label: 'Rate the cleaning quality of each area:',
rows: () => {
const rooms = roomsSection.checkboxList('roomsCleaned')?.value() || [];
const roomLabels: Record<string, string> = {
'kitchen': 'Kitchen',
'bathrooms': 'Bathroom(s)',
'living': 'Living Room',
'bedrooms': 'Bedroom(s)',
'dining': 'Dining Room',
'office': 'Home Office',
'laundry': 'Laundry Room',
'common': 'Common Areas'
};
 
if (rooms.length === 0) {
return [
{ id: 'overall', label: 'Overall Cleanliness', isRequired: true }
];
}
 
return rooms.map(room => ({
id: room,
label: roomLabels[room] || room
}));
},
columns: [
{ id: 'needs_work', label: 'Needs Work' },
{ id: 'acceptable', label: 'Acceptable' },
{ id: 'good', label: 'Good' },
{ id: 'spotless', label: 'Spotless' }
],
striped: true,
fullWidth: true,
isVisible: () => {
const rooms = roomsSection.checkboxList('roomsCleaned')?.value() || [];
return rooms.length > 0;
}
});
});
 
// ============================================
// SECTION 4: Thoroughness Check
// ============================================
const thoroughnessSection = form.addSubform('thoroughness', {
title: 'Thoroughness',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
thoroughnessSection.addRow(row => {
row.addThumbRating('allTasksCompleted', {
label: 'Were all requested cleaning tasks completed?',
showLabels: true,
upLabel: 'Yes, all done',
downLabel: 'Something was missed',
size: 'lg',
alignment: 'center'
});
});
 
thoroughnessSection.addRow(row => {
row.addCheckboxList('missedAreas', {
label: 'What was missed? (select all that apply)',
options: [
{ id: 'dusting', name: 'Dusting (surfaces, fixtures)' },
{ id: 'floors', name: 'Floors (vacuuming, mopping)' },
{ id: 'surfaces', name: 'Surface wiping' },
{ id: 'mirrors', name: 'Mirrors/Glass' },
{ id: 'appliances', name: 'Appliance cleaning' },
{ id: 'trash', name: 'Trash removal' },
{ id: 'beds', name: 'Bed making' },
{ id: 'other', name: 'Other area' }
],
orientation: 'vertical',
isVisible: () => thoroughnessSection.thumbRating('allTasksCompleted')?.value() === 'down'
});
});
 
thoroughnessSection.addRow(row => {
row.addTextarea('missedDetails', {
label: 'Please describe what was missed',
placeholder: 'Help us understand so we can address it...',
rows: 2,
isVisible: () => thoroughnessSection.thumbRating('allTasksCompleted')?.value() === 'down'
});
});
 
// ============================================
// SECTION 5: Staff Rating
// ============================================
const staffSection = form.addSubform('staff', {
title: 'Cleaning Team',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
staffSection.addRow(row => {
row.addStarRating('staffRating', {
label: 'Rate the cleaning team overall',
maxStars: 5,
size: 'lg',
showCounter: true,
alignment: 'center'
});
});
 
staffSection.addSpacer({ height: '12px' });
 
staffSection.addRow(row => {
row.addSuggestionChips('staffPositives', {
label: 'What stood out about the team? (select all that apply)',
suggestions: [
{ id: 'professional', name: 'Professional' },
{ id: 'punctual', name: 'Punctual' },
{ id: 'thorough', name: 'Thorough' },
{ id: 'friendly', name: 'Friendly' },
{ id: 'respectful', name: 'Respectful of property' },
{ id: 'communicative', name: 'Good communication' },
{ id: 'efficient', name: 'Efficient' },
{ id: 'detail', name: 'Attention to detail' }
],
alignment: 'center'
});
});
 
// ============================================
// SECTION 6: Value Assessment
// ============================================
const valueSection = form.addSubform('value', {
title: 'Value for Money',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
valueSection.addRow(row => {
row.addSlider('valueRating', {
label: 'How would you rate the value for money?',
min: 1,
max: 10,
step: 1,
defaultValue: 7,
showValue: true
});
});
 
valueSection.addRow(row => {
row.addTextPanel('valueLabel', {
computedValue: () => {
const value = valueSection.slider('valueRating')?.value();
if (value === null || value === undefined) return '';
if (value <= 3) return '๐Ÿ˜Ÿ Poor value - Price too high for quality';
if (value <= 5) return '๐Ÿ˜ Fair value - Could be better';
if (value <= 7) return '๐Ÿ˜Š Good value - Worth the price';
if (value <= 9) return '๐Ÿ˜ƒ Great value - Quality exceeds price';
return '๐ŸŽ‰ Exceptional value!';
},
customStyles: () => {
const value = valueSection.slider('valueRating')?.value();
const baseStyles = { textAlign: 'center', padding: '8px', borderRadius: '8px', fontSize: '14px' };
if (value !== null && value !== undefined) {
if (value <= 3) return { ...baseStyles, backgroundColor: '#fee2e2' };
if (value <= 5) return { ...baseStyles, backgroundColor: '#fef3c7' };
if (value <= 7) return { ...baseStyles, backgroundColor: '#d9f99d' };
return { ...baseStyles, backgroundColor: '#bbf7d0' };
}
return baseStyles;
}
});
});
 
// ============================================
// SECTION 7: NPS
// ============================================
const npsSection = form.addSubform('nps', {
title: 'Recommendation',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null,
customStyles: () => {
const category = npsSection.ratingScale('npsScore')?.npsCategory();
if (category === 'promoter') return { backgroundColor: '#dcfce7', padding: '16px', borderRadius: '8px' };
if (category === 'passive') return { backgroundColor: '#fef3c7', padding: '16px', borderRadius: '8px' };
if (category === 'detractor') return { backgroundColor: '#fee2e2', padding: '16px', borderRadius: '8px' };
return { padding: '16px', borderRadius: '8px', border: '1px dashed #e2e8f0' };
}
});
 
npsSection.addRow(row => {
row.addRatingScale('npsScore', {
preset: 'nps',
label: 'How likely are you to recommend our cleaning service to friends or family?',
showCategoryLabel: true,
showSegmentColors: true,
showConfettiOnPromoter: true
});
});
 
// ============================================
// SECTION 8: Additional Feedback
// ============================================
const feedbackSection = form.addSubform('feedback', {
title: 'Additional Comments',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
feedbackSection.addSpacer({ height: '8px' });
 
feedbackSection.addRow(row => {
row.addTextarea('additionalComments', {
label: 'Any other feedback or suggestions?',
placeholder: 'Share anything else about your experience...',
rows: 3,
autoExpand: true
});
});
 
feedbackSection.addRow(row => {
row.addCheckbox('canContact', {
label: 'You may contact me to discuss this feedback'
});
});
 
feedbackSection.addRow(row => {
row.addEmail('contactEmail', {
label: 'Email address',
placeholder: 'your@email.com',
isRequired: () => feedbackSection.checkbox('canContact')?.value() === true,
isVisible: () => feedbackSection.checkbox('canContact')?.value() === true
});
});
 
// ============================================
// SECTION 9: Summary
// ============================================
const summarySection = form.addSubform('summary', {
title: 'Feedback Summary',
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
summarySection.addRow(row => {
row.addTextPanel('summaryContent', {
computedValue: () => {
const overallRating = satisfactionSection.starRating('overallRating')?.value();
const satisfaction = satisfactionSection.emojiRating('satisfaction')?.value();
const staffRating = staffSection.starRating('staffRating')?.value();
const valueRating = valueSection.slider('valueRating')?.value();
const npsScore = npsSection.ratingScale('npsScore')?.value();
const npsCategory = npsSection.ratingScale('npsScore')?.npsCategory();
const allCompleted = thoroughnessSection.thumbRating('allTasksCompleted')?.value();
const serviceType = serviceSection.radioButton('serviceType')?.value();
 
const serviceLabels: Record<string, string> = {
'regular': 'Regular Clean',
'deep': 'Deep Clean',
'move': 'Move In/Out',
'onetime': 'One-Time',
'office': 'Commercial'
};
 
const satisfactionLabels: Record<string, string> = {
'very-bad': '๐Ÿ˜ข Very Unsatisfied',
'bad': '๐Ÿ˜• Unsatisfied',
'neutral': '๐Ÿ˜ Neutral',
'good': '๐Ÿ˜Š Satisfied',
'excellent': '๐Ÿ˜ƒ Very Satisfied'
};
 
let summary = `๐Ÿงน Cleaning Service Feedback\n`;
summary += `${'โ•'.repeat(28)}\n\n`;
 
if (serviceType) {
summary += `๐Ÿ“‹ Service: ${serviceLabels[serviceType] || serviceType}\n`;
}
 
if (overallRating !== null && overallRating !== undefined) {
summary += `โญ Overall: ${'โญ'.repeat(overallRating)} (${overallRating}/5)\n`;
}
 
if (satisfaction) {
summary += `๐Ÿ’ญ Feeling: ${satisfactionLabels[satisfaction] || satisfaction}\n`;
}
 
if (staffRating !== null && staffRating !== undefined) {
summary += `๐Ÿ‘ฅ Team: ${'โญ'.repeat(staffRating)} (${staffRating}/5)\n`;
}
 
if (valueRating !== null && valueRating !== undefined) {
summary += `๐Ÿ’ฐ Value: ${valueRating}/10\n`;
}
 
if (allCompleted !== null && allCompleted !== undefined) {
summary += `\nโœ… All Tasks Done: ${allCompleted === 'up' ? 'Yes' : 'No'}`;
}
 
if (npsScore !== null && npsScore !== undefined) {
summary += `\n\n๐Ÿ“Š NPS: ${npsScore}/10 (${npsCategory?.charAt(0).toUpperCase()}${npsCategory?.slice(1)})`;
}
 
return summary;
},
customStyles: () => {
const rating = satisfactionSection.starRating('overallRating')?.value();
const baseStyles = {
padding: '16px',
borderRadius: '8px',
whiteSpace: 'pre-wrap',
fontFamily: 'monospace',
fontSize: '14px'
};
 
if (rating !== null && rating !== undefined) {
if (rating >= 4) {
return { ...baseStyles, backgroundColor: '#dcfce7', borderLeft: '4px solid #22c55e' };
} else if (rating >= 3) {
return { ...baseStyles, backgroundColor: '#fef9c3', borderLeft: '4px solid #eab308' };
} else {
return { ...baseStyles, backgroundColor: '#fee2e2', borderLeft: '4px solid #ef4444' };
}
}
return baseStyles;
}
});
});
 
// ============================================
// FORM CONFIGURATION
// ============================================
form.configureSubmitButton({
label: () => {
const rating = satisfactionSection.starRating('overallRating')?.value();
if (rating !== null && rating !== undefined && rating >= 5) return 'Submit Glowing Review';
return 'Submit Feedback';
},
isVisible: () => satisfactionSection.starRating('overallRating')?.value() !== null
});
 
form.configureCompletionScreen({
type: 'text',
title: () => {
const rating = satisfactionSection.starRating('overallRating')?.value();
if (rating !== null && rating !== undefined && rating >= 4) return 'Thank you for the great feedback!';
return 'Thank you for your feedback';
},
message: () => {
const rating = satisfactionSection.starRating('overallRating')?.value();
const allCompleted = thoroughnessSection.thumbRating('allTasksCompleted')?.value();
 
if (allCompleted === 'down') {
return "We're sorry some tasks were missed. Our team lead has been notified and will follow up to make it right. Thank you for letting us know.";
}
if (rating !== null && rating !== undefined && rating <= 3) {
return "We're sorry this cleaning didn't meet your expectations. Our quality team will review your feedback and reach out to discuss how we can improve.";
}
return "Your feedback helps us maintain high standards. We look forward to your next cleaning!";
}
});
}
 

Frequently Asked Questions

When should I send cleaning feedback surveys?

Send within 24 hours of service completion while the experience is fresh. For recurring clients, survey after every 3-4 visits to avoid fatigue. Always survey after first-time services and any complaints. Consider same-day SMS surveys for quick responses.

How do I improve cleaning quality based on feedback?

Track ratings by cleaner and by area (kitchen, bathroom, etc.). Address specific complaints within 24 hours. Create checklists from feedback patterns. Share positive feedback with cleaners for motivation. Consider photo verification for recurring issues.

What's a good satisfaction score for cleaning services?

Aim for 4.5+/5 stars average. Industry benchmarks: Top cleaners maintain 4.8+. Scores below 4.0 indicate significant issues. Track trends - declining scores often predict cancellations. NPS above 50 is excellent for cleaning services.

Should I ask about pricing in cleaning feedback?

Yes, but carefully. Ask about 'value for money' rather than 'is it too expensive?' This tells you if clients feel they're getting quality worth the price. Include a separate field for pricing concerns to capture specific issues.

How do I handle negative cleaning feedback?

Respond within 4 hours for serious complaints. Offer a free re-clean for legitimate issues. Document patterns by cleaner for training. For recurring clients, proactive outreach prevents cancellations. Always thank clients for honest feedback.