How to track a customer feature request through a GitLab milestone without a dedicated roadmap tool
No, not by itself, and the part that actually bites is the ship date, not just the missing name. A GitLab milestone groups issues and merge requests around a due date, and GitLab's own docs describe exactly that: a shared target, a progress percentage, nothing about who asked for the work inside it. A milestone can tell you a batch of issues is due December 18th. It can't tell you that the CSV export in that batch is the one thing keeping a specific customer from renewing, and it can't tell you the export actually shipped by that date either, unless you put both pieces of information there yourself.
There's a second wrinkle worth knowing before you build anything on top of milestones. A milestone closes on its own once the due date passes, not when the issues inside it are done, when the calendar says so. GitLab states this plainly: "A milestone closes after its due date," and separately, "When a milestone is closed, its open issues remain open." So a milestone closing is not the same event as a request shipping, and if you're planning to notify anyone off that close event, you need to know it can fire on an empty promise.
What a milestone actually promises
A project milestone is available on every GitLab tier, including Free, and it can hold issues and merge requests from one project. A group milestone does the same across every project in a group. Either way, the object itself carries a title, a description, a start date, a due date, and a completion percentage calculated from closed work items. That's the whole contract. Nothing in a milestone's schema has a slot for "requested by," and GitLab's milestone webhook event confirms it from the other direction: the payload GitLab sends when a milestone is created, closed, reopened, or deleted carries id, title, description, state, and the two dates. No customer field, no subscriber list, nothing to loop in when the state changes to closed.
That's not a gap in GitLab's design so much as a scope decision. A milestone is a planning container. It was never meant to answer "who is waiting on this," the same way a calendar event doesn't tell you why you booked it.
Where the identity has to live instead
If you want a milestone's issues to carry who's waiting, you write it in yourself, and the two workable places are a label or the issue description. Labels are the more useful of the two because they're queryable: a customer::acme label lets you filter label:customer::acme across every project the customer touches, the way GitLab's own label docs describe scoped labels being used for exactly this kind of one-value-at-a-time classification.
Keep the taxonomy narrow on purpose. One label per customer account, applied at the moment the issue is filed, not batched later. If your team has already run into label sprawl on this tracker, the fix is the same one that works for any label sprawl: a small deliberate set beats an organic one every time, and customer labels are no exception. A description note works as a fallback for one-off mentions, but it isn't filterable, so treat it as a note to a human, not a system you can query later.
The webhook you can build, and what it still won't do
You can wire GitLab's Milestone Hook to fire on close and run a script that queries the Issues API for everything that was in that milestone, filtered to issues carrying a customer:: label. That gets you a list of accounts with something in the batch. It does not get you a list of accounts whose issue actually shipped, since a closed milestone and a closed issue are two different states. You'd need a second check against each issue's own state, and a third step to catch the second and third requesters who only ever showed up in a comment and never got a label at all, which means the automation only ever tells you about the requests someone remembered to tag on the way in.
When hand-tagging can't keep up
The label convention holds up fine for a handful of customer-tagged issues a month, one engineer keeping a mental map of who's in which milestone. It starts costing real time once requests arrive faster than anyone can tag them consistently, once two customers collide on the same scoped label, since a customer:: label holds one value per issue and adding a second one replaces the first rather than stacking with it, or once the same ask shows up in a support ticket and a sales call before it's ever a GitLab issue.
We'd suggest Modem once you're past that. Modem's GitLab integration watches merge requests, issues, and comments on the projects you connect, and ties the topic behind each one to the person and company who raised it, sourced from wherever the request actually came in, a support thread, a call transcript, a Slack mention, not only from a label someone remembered to apply. That also sidesteps the overwrite problem above, since Modem doesn't have to pick which requester a single label remembers. When two accounts want the same export, both show up against one topic instead of one label and one buried comment. When the issue actually ships, Modem already knows who both of them are, and the agent can draft the follow-up for you to approve, without anyone rechecking a closed milestone that already lied about the timeline once. Modem is our product, and this comparison comes from the company selling it, worth weighing as you read it; the label convention above still covers the volume most teams see before tagging turns into a full-time job. For the broader shape of what changes when the tagging habit gives out, see what a customer context graph is.
What to set up before the next milestone due date
Pick one label format, a customer:: prefix followed by the account name, and apply it the moment an issue is filed, not during a later cleanup pass. Then check any milestone you're relying on for a customer commitment against the issue's own state, not the milestone's, since a milestone can close on schedule while the work inside it is still unfinished. Those two habits catch most of what a bare milestone won't tell you on its own.
