# Handling incoming calls
In the previous section we added the capability of initiating the call. This section describes how to get notified of and handle incoming calls.
If you haven't yet initiated a call, go back and follow the steps in that [section](/docs/in-app-calling/getting-started/javascript/make-call).
## Listening for incoming calls
1. In `call-container` in `index.html` add the following HTML code:
```html
```
2. Inside the `SinchClientWrapper` `#sinchClientListener` `onClientStarted`-callback function, add the following code to add a listener for incoming calls:
```javascript
class SinchClientWrapper {
// ...
#sinchClientListener() {
return {
// ...
onClientStarted: (sinchClient) => {
console.log("Sinch - Start client succeded");
const { callClient } = sinchClient;
callClient.addListener({
onIncomingCall: (client, call) => {
this.ui.onIncomingCall(call);
this.#callListeners(call);
},
});
},
};
}
}
```
3. Inside the `UI`-class, add the following functions for handling callback for incoming calls from `SinchClientWrapper` and showing/hiding Answer and Hangup buttons:
```javascript
class UI {
// ...
onIncomingCall(call) {
console.log("Incoming call", call);
this.audio.srcObject = call.incomingStream;
this.onAnswer = this.#handleCall("answer", call, this.onAnswer);
this.onHangup = this.#handleCall("hangup", call, this.onHangup);
}
onCallEstablished(call) {
console.log("Call established", call);
this.#hideElement("answer");
this.#showElement("hangup");
}
onCallEnded(call) {
console.log("Call ended", call);
this.#hideElement("answer");
this.#hideElement("hangup");
}
#handleCall(id, call, oldOnClickFunction) {
const element = document.getElementById(id);
element.removeEventListener("click", oldOnClickFunction);
element.style = "display: block";
const onClickFunction = () => call[id]();
element.addEventListener("click", onClickFunction);
return onClickFunction;
}
// ...
}
```
4. If you followed all the steps, the files should look like this:
`index.html`
```html
```
`index.js`
```javascript
const APP_KEY = "enter-application-key";
const APP_SECRET = "enter-application-secret";
const ENVIRONMENT_HOST = "ocra.api.sinch.com";
class SinchClientWrapper {
constructor(userId, ui) {
this.userId = userId;
this.ui = ui;
const sinchClient = Sinch.getSinchClientBuilder()
.applicationKey(APP_KEY)
.userId(userId)
.environmentHost(ENVIRONMENT_HOST)
.build();
sinchClient.addListener(this.#sinchClientListener());
sinchClient.setSupportManagedPush();
sinchClient.start();
this.sinchClient = sinchClient;
}
async makeCall(callee) {
const call = await this.sinchClient.callClient.callUser(callee);
this.#callListeners(call);
return call;
}
#callListeners(currentCall) {
currentCall.addListener({
onCallProgressing: (call) => {
this.ui.onCallProgressing(call);
},
onCallEstablished: (call) => {
this.ui.onCallEstablished(call);
},
onCallEnded: (call) => {
this.ui.onCallEnded(call);
},
});
}
#sinchClientListener() {
return {
onClientStarted: (sinchClient) => {
console.log("Sinch - Start client succeded");
const { callClient } = sinchClient;
callClient.addListener({
onIncomingCall: (client, call) => {
this.ui.onIncomingCall(call);
this.#callListeners(call);
},
});
},
onClientFailed: (sinchClient, error) => {
console.log("Sinch - Start client failed");
console.error(error);
},
/**
* The recommended way to implement this authentication scheme
* is that the Application Secret should be kept securely on your
* server-side backend, the signed token should be created and
* signed on your server, then passed via a secure channel to
* the application instance and Sinch client running on a device.
*/
onCredentialsRequired: (sinchClient, clientRegistration) => {
new JWT(APP_KEY, APP_SECRET, this.userId)
.toJwt()
.then(clientRegistration.register)
.catch((error) => {
clientRegistration.registerFailed();
console.error(error);
});
},
};
}
}
class UI {
constructor() {
this.#handleLogin();
this.audio = new Audio();
this.audio.autoplay = true;
console.log("UI started");
}
onIncomingCall(call) {
console.log("Incoming call", call);
this.audio.srcObject = call.incomingStream;
this.onAnswer = this.#handleCall("answer", call, this.onAnswer);
this.onHangup = this.#handleCall("hangup", call, this.onHangup);
}
onCallProgressing(call) {
console.log("Call progressing", call);
}
onCallEstablished(call) {
console.log("Call established", call);
this.#hideElement("answer");
this.#showElement("hangup");
}
onCallEnded(call) {
console.log("Call ended", call);
this.#hideElement("answer");
this.#hideElement("hangup");
}
#handleCall(id, call, oldOnClickFunction) {
const element = document.getElementById(id);
element.removeEventListener("click", oldOnClickFunction);
element.style = "display: block";
const onClickFunction = () => call[id]();
element.addEventListener("click", onClickFunction);
return onClickFunction;
}
#hideElement(id) {
const element = document.getElementById(id);
element.style = "display: none";
}
#showElement(id) {
const element = document.getElementById(id);
element.style = "display: block";
}
#handleLogin() {
document.getElementById("login").addEventListener("click", () => {
const userId = document.getElementById("userid").value;
this.#hideElement("login-container");
this.sinchClientWrapper = new SinchClientWrapper(userId, this);
this.#handleMakeCallClick();
this.#showElement("call-container");
});
}
#handleMakeCallClick() {
document.getElementById("call").addEventListener("click", async () => {
const callee = document.getElementById("callee").value;
const call = await this.sinchClientWrapper.makeCall(callee);
this.audio.srcObject = call.incomingStream;
this.onHangup = this.#handleCall("hangup", call, this.onHangup);
});
}
}
new UI();
```
5. Open two tabs of the app and login as two different users. Enter the second user ID as callee in the first tab and press the "Call" button.
Click the "Answer" button and a you should see `Call established` in the console and hear audio confirmation that a call has
been established. You should also be able to press the "Hang Up" button if you want to cancel a current call or not answer.
## Next steps
Now that you've built a simple app to make and receive calls, learn more about the [JavaScript SDK](https://developers.sinch.com/docs/in-app-calling/js-cloud/).