Rostyslav Danylenko
← All case studies

City of Toronto · 2026

311 Toronto: Service Request Tracking

A municipal call-center goal became a UX investigation: why residents call, and how to close each reason at the source.

A lone City of Toronto 311 worker with a shovel facing a vast sprawl of city problems

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:

All of this overloaded the contact centre and delayed responses.

The initial analysis produced a mandate:

The result, in numbers:

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:

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.

Wireframe · Service Request tracking page. State before instruction decomposition: special instructions sit as one flattened block at the bottom.
Header
Breadcrumb
Page title
Search by reference number
Summary: request details + map
map
Status Tracking: the tracking mechanism
The part built here: status, milestones, staff notes, and photos. This is what turned silence into visible movement.
Special instructions: as-is
Everything dumped into one block at the bottom, ending in “call 311”. This is the problem the decomposition solved, shown separately as the Visibility Timeline.
Contact / call 311
Contact information
Related information
Footer
Low-fidelity wireframe · illustrative · not an official City of Toronto page

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.

Updates
Service request received
Completed · January 1, 2026

We received your service request and it’s waiting to be reviewed.

Inspection
Completed · January 2, 2026

We inspect the reported issue and make it safe if needed.

City staff notes
January 5, 2026

The area was fenced off for safety. The road surface was lined with cones.

Work started
Completed · January 6, 2026

We work on the issue based on safety, priority, and how many requests we receive.

City staff notes
January 6, 2026

Repair completed on site. The area is now safe for public use.

Closed
Completed · January 7, 2026

We’ve now closed your request. The reported issue was fixed if needed.

Additional information

We keep photos for six months after your request is closed. We may use AI to make notes clearer and remove personal information.

Anonymized portfolio reproduction · fictional data · photos replaced with placeholders

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.

1 · On entry
Location + problem-code check

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.

automatic
2 · On photo
AI photo match

AI compares the submitted photo-proof against existing requests to confirm whether it is the same issue.

automatic
3 · In the field
Inspector merges

If a duplicate slips through, the inspector on site merges the requests; both residents get one shared anonymized update.

manual
−89%
of duplicates caught by the first two automatic barriers.
The remaining ~11% reach the inspector and are merged in the field. Method: SR data analysis after launch (production).
Anonymized portfolio reproduction · internal problem codes removed.

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:

StageQuestions
Submission, what's next13
Assessment, routing, priority8
Work in progress10
Completion9
Cancellation and closure15
Total55

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:

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.

Each instruction lands at the intersection of the two axes: its place by importance, its moment in time.

Visibility Timeline
Vertical = page order (top → bottom). Horizontal = SR lifecycle (time →). Bars show when each block is visible; ✕ marks its removal condition.
NEW
always In Progress · never Future
ASSESSMENT
review / inspection
WORK
physical resolution
STALL
seasonal · optional
RESOLUTION
Closed · Cancelled
POST-RESOLUTION
Search / Lookup panel
permanent lookup
Safety escalation prompt
health & safety escalation · specific safety code · New
work starts
Active-incident reroute
active-incident rerouting · specific incident code · New
work starts
Summary
New / In Progress fields → Closed / Cancelled fields
Suggestion acknowledgement
removes tracking expectation · suggestion-type codes · New
work starts
Why was my request resolved?
final outcome explanation · all · Post-resolution (Closed & Cancelled)
could double as the status explanation
What to do if cancelled
exit / next steps · all · Post-resolution (Cancelled only)
Status Tracking (milestones + notes)
milestone states: Future / In Progress / Completed
What happens next
upfront process explanation · all · New
work starts
How we work and provide updates
operational / communication model · all · New–Resolution
Our responsibilities and limitations
false-expectation correction · ambiguous jurisdiction · New–Resolution
How we prioritize
prioritization explanation · prioritization expectation · New–Resolution
How long it will take
timing expectation · where an estimate exists · New–Resolution
Good to know
service-specific nuances · with nuances · New–Resolution
Final-status logic
what completed / closed / cancelled means · all · New–Resolution
Stay updated
update subscription · when not subscribed · New–Resolution
Need help or updates?
next-action / support · all · New–Resolution
Contact Information
permanent contact block
Stationary panel: page backbone
Special instruction: existing (evidenced)
Proposed instruction
appears
removal condition
Dashed border = proposed / conditionalTinted column = optional stall (seasonal)
Branching. Closed = resolved successfully; Cancelled = cannot resolve (no problem found / not located). Blocked at Assessment → work phases skipped; blocked late → all phases run, then Cancelled. A seasonal stall may delay Closed by months.
Anonymized portfolio reproduction · internal problem codes removed · fictional where noted.

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.

That made the contact centre a last resort, after every explanation and every exit.

header
breadcrumb

Service Request Status

search block
Road or sidewalk maintenance
Reference number01234567Status
Cancelled
This request was cancelled on May 14, 2026: no issue was found at the location described.
LocationToronto, ON
Map
What to do if your request has been cancelled
  • See the specific reason your request was cancelled.
  • Submit a new request if the problem isn’t resolved.
  • Tell us if you disagree with the outcome.
Status Tracking
Additional information

Photos are kept for six months after your request is closed. Some notes may be edited by AI for clarity and to remove personal details.

simplified for context

If you have questions about your request, call 311 and we’ll help.

footer
Anonymized portfolio reproduction · fictional data · not an official City of Toronto page

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.

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.

Have a question about this project?

No pressure, ask about the approach, the numbers, or anything that’s unclear.