Programmatically find the canister id of a frontend canister

In one of my motoko actor canisters, I need to generate a URL that points to my frontend asset canister. To do this, I need the cid of the asset canister.

AFAIK it’s not possible to import a frontend canister and use Principal.toText(Principal.fromActor(MyCanister)) since there is no Actor.

How do I find the cid of a frontend canister?

I am currently looking for the same thing (from Motoko).
Did you find the solution ?

Something like this

import Principal "mo:base/Principal";

actor MyActor {
   
   public shared query func myId() : async (Text) {
    let self : Principal = Principal.fromActor(MyActor);

    return Principal.toText(self);
  };

};

Not really…
Let’s assume a request from the frontend canister to the backend canister.

public shared (msg) func test() : async () {
    // Print the frontend canister Principal
    Debug.print(debug_show(msg.caller));
  };

It prints “2vxsx-fae” as anonymous Principal.

I think I need to sign the request from the frontend canister but despite my research, I’m having trouble figuring out which JS library to use.

The frontend canister id can be retrieved from the generated declaration folder, so it’s not supposed to be anonymous…

export const canisterId = process.env.app_FRONTEND_CANISTER_ID;

It’s the anonymous ID for you because you don’t have a logged-in user. When the agent isn’t logged in, all calls will look like they’re coming from the anonymous identity.

I used @kpeacock’s excellent ic-avatar demo to learn how to properly log in a user.

Once logged in, the code you shared above will report the user’s principal, at least for the first call into the backend. If your backend code calls another function, the principal reported through msg.caller will be the cid of the backend canister (read more here). As far as I know, it’s impossible to get the cid of the frontend canister itself without examining the source files (the declarations folder as you mentioned, or .dfx/local/canister_ids.json), which is impossible to do in Motoko.

Because I needed the frontend cid when responding inside http_request in a Motoko file, my hacky workaround for now is to pass in the frontend cid as a query param, and parse that within http_request. Not ideal, but it let me continue my work.

I use the following code in a .tsx file in the frontend (so it’s not useful for finding the frontend cid solely from Motoko which is necessary when responding to http_request since that doesn’t go through the frontend at all), but for normal use cases with the frontend talking to the backend, it can be passed in via a parameter to the backend if necessary):

const frontendCid = window.location.origin.split('//')[1].split('.')[0];

Depending on your webpack setup, you may also be able to retrieve the frontend cid from within the frontend using the environment variable webpack sets up, for example I can access mine in a .tsx file using the following:

const canisterId = process.env.FRONTEND_CANISTER_ID;

Since the environment variable was set up by webpack:

new webpack.EnvironmentPlugin({
  FRONTEND_CANISTER_ID: canisters["frontend"]
})

But again, that doesn’t help if you’re trying to get the cid from the backend inside of, for example, http_request which never goes through the frontend.

Probably a more robust solution to this problem would involve a pre-compile (mid-compile?) step to examine the generated .dfx or declarations folder to discover the frontend cid and insert it into the backend code before compilation finishes.

1 Like