City of Toronto: 311 Service Tracking
How a combined approach solved one large problem
Role: Senior UX/UI Designer, IC. Team: 30+ people, about ten roles. Service designers wrote content. UX/UI for the tracking pages was mine. Period: six months. Context: public sector, the municipal 311 Toronto service: 9 divisions, 600+ problem codes.
Overview
This is a story about how one resident's bad experience set off a chain of changes across ten city departments and improved public-service quality on Toronto's main 311 service portal.
A city councillor once contacted 311 Toronto with a routine request, as an ordinary resident, and ran into two problems that pushed him to call the contact centre more than once: at request creation, and while waiting for status updates. That led to an uncomfortable discovery:
- Residents can't find the right service on the portal. After an hour of searching, they call the contact centre to have the request made for them.
- After submitting a request, the resident gets no status updates. They don't know what's happening next, and call the contact centre again.
- Different residents often create identical requests without knowing about each other. Requests get duplicated.
- These calls added up to more than 50,000 a month.
All of this overloaded the contact centre and delayed responses.
The initial analysis produced a mandate:
- simplify finding and submitting a service on the portal;
- cut overall contact-centre load by 30%.
The result, in numbers:
- duplicate requests: down 89%;
- repeat calls to the contact centre: down 46%;
- overall contact-centre calls: down 28% against a 30% target.
The mandate was met through a combination of measures that together produced a strong result and became the foundation for further research and improvements to the 311 Toronto portal.
My role
I owned UX/UI for the tracking pages, from research through handoff to development. I also owned the decomposition and presentation of special instructions (sorting them by importance and lifecycle, and their placement rules) and mapped the street-test questions across the request's lifecycle stages. Service designers wrote the content. Research was done together. The deduplication mechanism was built by the team; I contributed to the decisions behind it. Work went through several iterations, from an MVP concept to alpha and beta versions, with new features added and page complexity growing over time.
The log review that set the direction
The target was a number. A number doesn't say what to build. The first step was two studies: a review of contact-centre logs and interviews with contact-centre staff. Design waited.
Problems arose at different points along the service-request journey, from finding the service to post-resolution. Each point drove its own call, often several from the same residents. The logs and interviews sorted them into causes:
- Service search is broken. Among 600 options, the resident can't find the right one. They call and say "just create the request for me."
- Request creation is unclear. The resident doesn't understand how to submit. They call and say "help me create it."
- No tracking page. They submitted a request and see nothing. They call and ask "what's happening with my request?"
- Cancelled with no explanation. The status changes to Cancelled. They call and ask "why was it cancelled?"
- Duplicates. Several residents submit a request for the same issue without knowing about each other.
The first two points (search and creation) belonged to other teams. The rest was ours: tracking, Cancelled, duplicates. Each cause went on to get its own mechanism.
The tracking page: silence after submission
The biggest driver of calls was that residents saw nothing. They submitted a request and waited in the dark.
The solution came from the team, not handed down from above. Together with the service designers, we built the tracking-page concept, brought it to leadership, and it shipped to production.
I designed the page to give residents what was missing: request status, milestones showing where the request stood, notes from city staff, and photos from the location (what's happening there, how the issue is being resolved). A resident opens the page and sees movement instead of silence.
The page closed the biggest driver of calls: silence after submission. It's one component of the overall drop in contact-centre load.
Duplicates: a double cost to the city
A separate problem surfaced in the logs: several neighbours creating a request for the same issue.
A pothole. Everyone who walks past it sees it and files their own SR. For the city, every duplicate is a new request: the inspector goes out again to the same spot, staff show up more than once to resolve one issue. It's not just an extra row in the database. It's field resources spent twice, sometimes three times over.
We traced where duplicates came from and set up three barriers, at different points in the request's lifecycle.
On entry. When a resident creates an SR, the system checks location and problem code. If a request already exists for it, we show that the city is already on it and offer an anonymized update on the outcome instead.
On photo. If the resident still creates a separate request, we ask for photo proof of the issue. AI checks whether it's the same request or a new one. If AI confirms a duplicate, both requests are automatically merged into one, and each resident gets an anonymized update. They never learn about each other.
In the field. If AI missed it and the duplicate reaches the field, the inspector on site spots the repeat and has a tool to merge the requests into one. Both residents get a shared, anonymized update.
The first two barriers cut duplicates by 89%. The rest (about 11%, per the study) reached the inspector and were merged in the field. Method: SR data analysis after launch. Production.
Deduplication: three barriers
Where duplicate service requests are caught along the request lifecycle.
The system compares a new request against open ones at the same place. On a match, the resident is offered an anonymized update instead of a new request.
AI compares the submitted photo-proof against existing requests to confirm whether it is the same issue.
If a duplicate slips through, the inspector on site merges the requests; both residents get one shared anonymized update.
The street test: the next layer of questions
The page shipped and closed the main gap. But we were still two points short of the target, and went out to check what was left.
The method was direct. Service designers and I went out on the street with a laptop, stopped passers-by, showed clickable prototypes, and interviewed people. The first round produced 55 questions from real residents. I mapped them across the request's lifecycle stages:
| Stage | Questions |
|---|---|
| Submission, what's next | 13 |
| Assessment, routing, priority | 8 |
| Work in progress | 10 |
| Completion | 9 |
| Cancellation and closure | 15 |
| Total | 55 |
The biggest cluster landed at the end. Fifteen questions about cancellation, nine about completion: over a quarter of all questions were about the request's final outcome, not its progress. Was it fixed, or just closed. Why was it closed if the problem is still there. What do I do if I disagree.
The page had already solved the main problem. The test showed where to dig next: into explaining the process. People still didn't understand how the city was handling their request at each stage.
Decomposing the special instructions
The source for these explanations was meant to be the special instructions: text tied to each request by division and problem code. But they were broken.
Six hundred instructions, nine divisions. Each division had its own set, unstructured, dumped together, often outdated and written in technical language. The whole block landed on the page as-is.
Here's what a pothole instruction looked like, everything dumped into one block at the bottom of the page:
- what happens next;
- how long to wait, by road type;
- things to know;
- why the request might get closed.
And a final line:
If you have questions or would like more information, please call 311 and we'll be happy to help.
Text meant to take load off the contact centre ended with a suggestion to call the contact centre.
Look at one instruction and it's just a long block of text. Look at a hundred and a system appears. First, every instruction was run through one question: what should it do after the request is submitted, and what's generic, off-stage, or redundant. Then the set was sorted along two axes.
- By hierarchy of importance. The page is built around the resident's questions: is this my request; what's the status; what's happened so far; why is this taking long; what does the outcome mean; do I need to do anything. These questions set the order: safety, confirmation, progress, explanation, expectations, and support stop competing for attention.
- By request lifecycle. Every instruction was mapped across the lifecycle: when it appears, how long it stays, what condition removes it. This makes visible where blocks overlap, which stages are overloaded, what already exists, and what still needs to be built.
Each instruction lands at the intersection of the two axes: its place by importance, its moment in time.
The work then split. Service designers brought the old instructions to a proper standard: readability, structure, consistency across divisions. I proposed additional instructions to close four gaps in the questions residents were asking that the old set didn't answer. Together with the service designers, we refined them, and some went into production.
The scattered set became a structured UX content system. The breakdown was carried through to a concept and user testing. Some decisions still carried an "Open question for team review" tag. The case doesn't attach a separate figure to it.
Cancelled: rejection without explanation
The negative outcome drove the largest share of questions, and became the clearest case of decomposition in action: four instructions from the set, placed by importance and by lifecycle.
Cancelled landed like a wall. A resident got an email saying "request cancelled," didn't understand why, and called. What went wrong. What to do next. The standard "call 311" on the page answered nothing. It generated exactly the call it was supposed to prevent.
Cancellation complaints came in two types: the person disagreed with the decision, or the problem was still physically there.
The solution was split across several special instructions. Each appeared at its own time and place on the tracking page.
- The first instruction: right after the service request is created. It gently introduces the person to possible closure outcomes and reasons, like an incorrect location or an inspector not finding the issue. Each reason prepares the resident for a possible negative outcome. Knowing this in advance, a Cancelled status no longer hits like a wall. Once the request is closed, the instruction disappears.
- Once Cancelled hits: two instructions for two levels of frustration. A status description at the top, in the summary panel, explains the specific reason for rejection. An info notice below the summary offers a few ways forward, without needing to call the contact centre.
- The call: the last block at the bottom. If none of the exits fit, we point to the hotline; an agent can help by voice.
That made the contact centre a last resort, after every explanation and every exit.
Service Request Status
If you have questions about your request, call 311 and we’ll help.
Most of the time, that was enough. Residents read the explanation, understood the rejection, and accepted it. No new request followed. Repeat contacts down 46%. Method: contact-centre log analysis. Production. Total call volume dropped too. That contribution fed into the overall load analysis.
Result
State as of my time on the project. The metrics differ in nature, so they're named separately.
- Duplicate requests: down 89%. Delivered by the first two automatic barriers: the location-and-code check on entry, and the AI photo match. The rest (about 11%, per the study) reached the inspector and was merged in the field. Method: SR data analysis after launch. Production.
- Repeat contacts: down 46%. Explaining the exits from a Cancelled status: residents understood the rejection and didn't resubmit. Method: contact-centre log analysis. Production.
- Contact-centre load: down 28% against a 30% target. A combined effect of several mechanisms. The tracking page closed the biggest driver: silence after submission. Special instructions guided residents through Cancelled toward reference material and additional exits. Deduplication cut total request volume. Search and submission belonged to other teams, outside this case. Method: beta testing at launch. Beta.
The whole effort took six months. All three directions trace back to one source: the contact-centre log review at the start.
Reflection
Two lessons.
The first is about the number in the brief. A "minus 30%" target contains no solution. It contains a question: why 50,000 calls in the first place. The logs showed calls originating at different points along the request's journey. Search and request creation belonged to other teams. The rest was ours: silence after submission, an unexplained Cancelled, duplicates. Each cause got its own mechanism. The causes fed each other, too: without merging, an inspector would cancel a duplicate, and every cancelled duplicate became a new "why was this cancelled" question.
The second is about the instructions. Six hundred pieces of text looked like a content task. It was information architecture. When a resident understands the process and its possible outcomes in advance, the need to call disappears. What decides that is where the text sits: by importance, and by its moment in the request's life.