A simple workaround is to use path bindings :
In your routes :
Dispatch = cowboy_router:compile([
%% {HostMatch, list({PathMatch, Handler, Opts})}
{'_', [{"/echo/:echo", my_handler, []}]}
]),
Then in your code :
{Echo, Req2} = cowboy_req(echo,Req)
It's best to do this in Websocket_handle because you will be able to send your response to the socket. In init, you will have to carry it in your state, like this :
websocket_init(_TransportName, Req, _Opts) ->
{Echo, Req2} = cowboy_req:binding(echo,Req),
erlang:start_timer(1000, self(), <<"Hello!">>),
{ok, Req2, {Echo}}.
websocket_handle(_Frame, Req, {Echo}) ->
{reply, {text, Echo}, Req, State}.
As websocket is designed to handle long term connections, i use bindings like this to support information like channels, user ids, etc. But not data like in "echo" because you will want to send multiple different texts to echo without closing and reopen a websocket connection each time just to change URL.